Question

J'utilise un tableau avec un rendu de cellule qui me permet de placer un bouton "x" dans chaque cellule avec une valeur afin que je puisse supprimer la valeur de la cellule en appuyant sur le bouton. L'éditeur de cellule affecte l'écouteur d'actions au bouton et les actions appropriées sont appelées lorsque le bouton est enfoncé.

Chaque colonne du modèle de table qui est un DefaultTableModel est remplie par une liste de tableaux de valeurs. J'ai réussi à supprimer la bonne valeur de la liste des tableaux en appuyant sur le bouton et toutes les autres cellules du tableau s'actualisent après le changement, mais la cellule dont la valeur a été supprimée reste inchangée. Si je redémarre l'application ou ajoute une valeur à la liste des tableaux, la table s'actualise comme prévu et tout semble comme il se doit.

Le problème Mo est qu'il semble que le moteur de rendu de cellule n'oublie pas la valeur initiale de la cellule et continue donc toujours à imprimer cette valeur dans la cellule même si le tableau est redessiné. Quelqu'un a-t-il une idée de la façon dont je pourrais actualiser correctement le tableau afin que les valeurs soient correctement affichées?

Classe de table:

public class Table extends JTable {

public static DefaultTableModel model = new DefaultTableModel();
private Days d;
private JFrame frame;
private AddCellRenderer renderer;
private AddCellEditor editor;

public Table(Days d, JFrame frame) {
    // Assign the table model to the table
    super(model);
    this.d = d;
    this.frame = frame;

    // Define dimensions of table
    model.setRowCount(11);
    model.setColumnCount(5);

    // Block resizing and reordering of headers
    this.setColumnSelectionAllowed(false);
    this.setRowSelectionAllowed(false);
    this.setCellSelectionEnabled(true);
    this.setTableHeader(null);

    // Define first row height
    this.setRowHeight(38);
    // Define all other row's heights
    this.setRowHeight(0, 45);

    this.d.setTable(this);

    for (int i = 0; i < 5; i++) {
        editor = new AddCellEditor(new JCheckBox(), d.getVisibleDays().get(i), this);
        renderer = new AddCellRenderer(d.getVisibleDays().get(i), editor);
        this.getColumnModel().getColumn(i).setCellRenderer(renderer);
        this.getColumnModel().getColumn(i).setCellEditor(editor);
    }

    this.refresh();
}

public void refresh() {

    // Empty table
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 11; j++) {
            this.getModel().setValueAt(null, j, i);
        }
    }

    // Populate table with entries for each day
    for (int i = 0; i < 5; i++) {

        Iterator<String> iterator = d.getVisibleDays().get(i).getEntryListIterator();

        int j = 0;

        while(iterator.hasNext()){
            String s = iterator.next();
            this.getModel().setValueAt(s, (j+1), i);
            j++;
        }

        this.getModel().setValueAt(d.getVisibleDays().get(i).getDayName(), 0, i);
    }
}

public void modelClearValueAt(int row, int column) {
    this.getModel().setValueAt(null, row, column);
}
}

Classe d'éditeur de cellule:

public class AddCellEditor extends DefaultCellEditor {

private JPanel headerPanel;
private JPanel entryPanel;
private JLabel dayName;
private JLabel entryValue;
protected JButton addButton;
private JButton removeButton;
private String label;
private int row;
private int column;
private Day day;
private String date;
private Table table;
private AddCellRenderer renderer;

public AddCellEditor(JCheckBox checkBox, Day day, Table table) {
    super(checkBox);
    this.day = day;
    this.table = table;
    date = day.getDayDate();
    headerPanel = new JPanel();
    headerPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
    entryPanel = new JPanel();
    entryPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
    dayName = new JLabel();
    entryValue = new JLabel();
    addButton = new JButton();
    removeButton = new JButton();
    headerPanel.add(dayName);
    headerPanel.add(addButton);
    entryPanel.add(entryValue);
    entryPanel.add(removeButton);
    addButton.setOpaque(true);
    addButton.setPreferredSize(new Dimension(16, 16));
    removeButton.setOpaque(true);
    removeButton.setPreferredSize(new Dimension(16, 16));
    addButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            System.out.println("Add pressed");
            addItem();
            fireEditingStopped();
        }
    });
    removeButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            System.out.println("Remove pressed");
            removeItem();
            getTable().refresh();
            fireEditingStopped();
        }
    });

}

public void setRenderer(AddCellRenderer renderer) {
    this.renderer = renderer;
}

public Component getTableCellEditorComponent(JTable table, 
        Object value, boolean isSelected, int row, int column) {

    this.row = row;
    this.column = column;

    if (row == 0) {
         return this.headerPanel;
    }
    if (row != 0 && value != null) {
        return this.entryPanel;
    }
    return null;
}

public void addItem() {
    String input = JOptionPane.showInputDialog("Add entry for " + label + ":");

    if ((input != null) && (input.length() > 0)) {
        System.out.println("Added: " + input + "Item");
        day.addEntry(input, column);
    }
}

public void removeItem() {
    table.modelClearValueAt(row, column);
    day.removeEntry(row-1);
    System.out.println("Item removed");
}

public Table getTable() {
    return this.table;
}

public boolean stopCellEditing() {
    return super.stopCellEditing();
}

protected void fireEditingStopped() {
    super.fireEditingStopped();
}
}

Merci d'avance

Était-ce utile?

La solution

d'accord, je n'ai pas pu résister (l'alternative est de frotter la salle de bain :-)

Voici un aperçu très brut (juste assez pour vous donner une idée) de la façon de résoudre votre objectif avec un éditeur bien comporté et un tableModel personnalisé.

  • MyTableModel est une implémentation personnalisée essentiellement soutenue par une liste d'entrées arbitraires
  • ce tableModel prend en charge la suppression / l'ajout d'éléments. En privé pour le moment, vous n'êtes donc pas tenté de les appeler depuis l'éditeur :-) Ils sont suffisamment sûrs pour être exposés avec une portée publique, si nécessaire, f.i. si d'autres parties du programme doivent également modifier les entrées
  • le modèle peut gérer différents types de valeurs dans setValueAt: un marqueur Modify, un NewEntry ou une valeur simple
  • l'éditeur personnalisé est un panneau avec des boutons pour supprimer, ajouter une ligne.
  • les actions du bouton définissent la valeur editorValue comme il convient avant d'appeler editStopped / cancelled comme nécessaire

Le modèle:

public static class MyTableModel extends AbstractTableModel {

    public enum Modify {
        ADD,
        REMOVE
    }

    public static class NewItem {
        public final Object entry;

        public NewItem(Object entry) {
            this.entry = entry;
        }
    }

    private List entries;

    public MyTableModel(List entries) {
        this.entries = entries;
    }

    @Override
    public int getRowCount() {
        return entries.size();
    }

    @Override
    public int getColumnCount() {
        return 1;
    }


    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
        return true;
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        return entries.get(rowIndex);
    }

    @Override
    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
        if (aValue instanceof NewItem) {
            addEntry(((NewItem) aValue).entry);
        } else if (Modify.REMOVE == aValue) {
            removeEntry(rowIndex);
        } else {
            entries.set(rowIndex, aValue);
        }    
    }

    private void removeEntry(int rowIndex) {
        entries.remove(rowIndex);
        fireTableRowsDeleted(rowIndex, rowIndex);
    }

    private void addEntry(Object aValue) {
        int last = getRowCount();
        entries.add(aValue);
        fireTableRowsInserted(last, last);
    }


}

L'éditeur:

public static class MyCellEditor extends AbstractCellEditor implements TableCellEditor {

    private Object editorValue;
    private JLabel entryView;
    JComponent editor;

    public MyCellEditor() {
        editor = new JPanel();
        entryView = new JLabel();
        editor.add(entryView);
        Action add = createAddAction();
        editor.add(new JButton(add));
        Action remove = createRemoveAction();
        editor.add(new JButton(remove));
    }

    public Action createRemoveAction() {
        Action remove = new AbstractAction("Remove Entry") {

            @Override
            public void actionPerformed(ActionEvent e) {
                editorValue = MyTableModel.Modify.REMOVE;
                fireEditingStopped();
            }

        };
        return remove;
    }

    public Action createAddAction() {
        Action add = new AbstractAction("Add Entry") {

            @Override
            public void actionPerformed(ActionEvent e) {
                String input = JOptionPane.showInputDialog("Add entry: ");

                if ((input != null) && (input.length() > 0)) {
                    editorValue = new MyTableModel.NewItem(input);
                    fireEditingStopped();
                } else {
                    fireEditingCanceled();
                }

            }

        };
        return add;
    }

    @Override
    public Object getCellEditorValue() {
        return editorValue;
    }

    @Override
    public Component getTableCellEditorComponent(JTable table,
            Object value, boolean isSelected, int row, int column) {
        entryView.setText(value != null ? value.toString() : "");
        return editor;
    }


}

L'utilisation:

    List entries = new ArrayList();
    for (int i = 0; i < 5; i++) {
        entries.add("entry " + i);
    }
    TableModel model = new MyTableModel(entries);
    JTable table = new JTable(model);
    table.getColumnModel().getColumn(0).setCellEditor(new MyCellEditor());
    table.getColumnModel().getColumn(0).setPreferredWidth(200);
    table.setRowHeight(50);

Autres conseils

Si vous utilisez un DefaultTableModel, vous devrez alors supprimer la valeur détenue par le modèle lui-même, et non la valeur de la ArrayList utilisée pour construire le modèle.Vous feriez cela en appelant la méthode setValueAt(...) de l'objet DefaultTableModel.

Vous souhaiterez peut-être publier un SSCCE pour obtenir une aide plus spécifique.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top