checkbox

Hallo Zusammen,

ich habe eine Frage zu folgendem Codeschnipsel. Das ist ein Auszug eines TableCellRenderers für einen JTable.

Code:
     @Override
            public Component getTableCellRendererComponent(JTable table, Object value, boolean arg2, boolean arg3, int row,
                    int column) {
           
             JTextField editor = new JTextField ();
         
            System.out.println("OK");

                    String s = (String) table.getValueAt(row, 11);
                   
                   
                    switch (s) {
                    case  "Komplettlieferung" :
                        if (checkKomplettlieferung.isSelected()) {
                        editor.setBackground(Color.YELLOW);
                        } else {
                            table.setRowHeight(row, 1);
                        }
                    break;
Was tut das Ding? Wenn die CheckBox checkKomplettlieferung ausgewählt ist (also mit Häkchen), wird die Zeile ganz normal und mit gelbem Background angezeigt. Wenn die CheckBox nicht angetickert ist, wird die Zeile quasi ausgeblendet (Das mit der Höhe auf 1 Pixel setzten ist noch eine Notlösung, mangels Fund einer Methode zum Ausblenden).

Mir geht es jetzt aber darum. Wenn die Checkbox nicht angetickert ist, und die Zeile somit ausgeblendet ist, befindet sich der Renderer irgendwie in einer Endlosschleife. Das habe ich über die Testausgabe "OK" in der Konsole festgestellt. Die läuft das endlos weiter. Setze ich das Häckchen wieder, wird die Zeile wieder normal angezeigt und "OK" wird nicht weiter ausgegeben.

Wie kommt das? Müsste der EDT nicht nur einmal prüfen, ob Häckchen gesetzt oder nicht und dann die entsprechende Aktion ausführen?

Ach ja, im Übrigen sieht der Action Listener für diue checkbox ganz simple einfach so aus,


Code:
   public class statusSorter implements ActionListener {
       
        @Override
        public void actionPerformed(ActionEvent e) {
           
           
            model.tableChanged();
   
     

    }
    }

Ich danke für eure Gedankenstöße.
Oli
 
Wie kommt das? Müsste der EDT nicht nur einmal prüfen, ob Häckchen gesetzt oder nicht und dann die entsprechende Aktion ausführen?
Nein, Du änderst die Tabelle, dadurch wird ein repaint() Ereignis in die EventQueue gelegt. Beim repaint() wird dann Dein renderer erneut ausgeführt, der setzt wieder die Zeilenhöhe auf 1 usw.

mangels Fund einer Methode zum Ausblenden
Es braucht keine Methode zum Ausblenden: das Model enthält alles, was angezeigt wird... ;)
 
Nein, Du änderst die Tabelle, dadurch wird ein repaint() Ereignis in die EventQueue gelegt. Beim repaint() wird dann Dein renderer erneut ausgeführt, der setzt wieder die Zeilenhöhe auf 1 usw.


Es braucht keine Methode zum Ausblenden: das Model enthält alles, was angezeigt wird... ;)
Dank Dir. Verstanden. Ich habe die Switch Abfrage jetzt direkt in den Action listener eingebaut und der Fehler ist behoben.
Stimmt. Macht keinen Sinn, den Table innerhalb des Renderers immer wieder zu ändern.

Aber zu Antwort Teil 2:
Der Datensatz soll im Model nicht gelöscht werden. Der soll im Table nur nicht angezeigt werden, wenn ein entsprechender Haken in einer Checkbox entfernt wird. Wird der Haken dann wieder gesetzt, so wird der Datensatz wieder angezeigt.
Mit dem "Höhentrick" funktioniert das ganz gut, hat aber den Nachteil, daß bei großen Listen auch die Zeilen mit 1 Pixel Höhe zu sehen sind, wenn viele davon hintereinander liegen.
 
Der Datensatz soll im Model nicht gelöscht werden. Der soll im Table nur nicht angezeigt werden
Du darfst das TableModel nicht mit dem Domainmodel verwechseln. Das TableModel liefert einfach die Daten, die von einer View (konkret z. B. JTable) angezeigt werden sollen. Ob ein Datum aus dem TableModel aufgrund eines Filters fliegt oder tatsächlich entsprechende Okjekte im Domainmodel entfernt werden, ist irrelevant. Die Ereignisse, die vom TableModel ausgelöst werden, beziehen sich auch nur auf das TableModel selbst.

Daher bedarf es weder einer Methode in JTable noch eines Höhentricks. Wenn Du eine Zeile ausblenden willst, dann ist das einfach eine Aufgabe des TableModels.
 
Du darfst das TableModel nicht mit dem Domainmodel verwechseln. Das TableModel liefert einfach die Daten, die von einer View (konkret z. B. JTable) angezeigt werden sollen. Ob ein Datum aus dem TableModel aufgrund eines Filters fliegt oder tatsächlich entsprechende Okjekte im Domainmodel entfernt werden, ist irrelevant. Die Ereignisse, die vom TableModel ausgelöst werden, beziehen sich auch nur auf das TableModel selbst.

Daher bedarf es weder einer Methode in JTable noch eines Höhentricks. Wenn Du eine Zeile ausblenden willst, dann ist das einfach eine Aufgabe des TableModels.
Okay, also das bedeutet, am Besten die getValueAt Methode aus dem Table Model entsprechend anpassen? Also entsprechende Filter direkt im Table Model setzen?
 
Du kannst auch ein neues TableModel als Filter für ein anderes schreiben. Unten ein Ansatz.

Java:
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;

public class Test {
    private static final String[] NAMES = {
        "Albers", "Schmidt", "Kruse", "Becker", "Cordes",
        "Menke", "Janssen", "Gerdes", "Eilers", "Kramer" };

    private static final String[] FIRST_NAMES = {
        "Jonas", "Luca", "Leon", "Finn", "Noah",
        "Liam", "Elias", "Paul", "Ben", "Julian",
        "Mia", "Emma", "Leonie", "Marie", "Sophia" };
    
    static class Person {
        public final int id;
        public final String name;
        public final String firstName;
        
        public Person(int id, String name, String firstName) {
            this.id = id; this.name = name; this.firstName = firstName; 
        }
    }


    static class PersonTable extends AbstractTableModel {
        private static final String[] COLUMNS = {
            "ID", "Name", "Vorname"
        };

        private List<Person> persons = new ArrayList<>();

        public PersonTable() {
            Random rand = new Random(1L);
            for (int i = 0; i < 100; i++) {
                persons.add(new Person(i+1,
                    NAMES[rand.nextInt(NAMES.length)],
                    FIRST_NAMES[rand.nextInt(FIRST_NAMES.length)]));
            }
        }    

        @Override
        public int getColumnCount() { return COLUMNS.length; }
        @Override
        public String getColumnName(int ix) { return COLUMNS[ix]; }
        @Override
        public int getRowCount() { return persons.size(); }
        @Override
        public Object getValueAt(int row, int col) {
            Person p = persons.get(row);
            switch(col) {
                case 0: return p.id;
                case 1: return p.name;
                case 2: return p.firstName;
            }
            return null;
        }
    }

    static class RowFilter extends AbstractTableModel {
        private final List<Integer> hidden = new ArrayList<>();
        private final TableModel model;
        public RowFilter(TableModel toFilter) {
            model = toFilter;
        }

        int modelIndex(int rowIndex) {
            int ix = Collections.binarySearch(hidden, rowIndex);
            int skip = ix < 0 ? -ix-1 : ix+1;
            return rowIndex + skip;
        }

        int rowIndex(int modelIndex) {            
            int ix = Collections.binarySearch(hidden, modelIndex);
            return ix < 0 ? modelIndex - (-ix-1) : -1;
        }

        public int hide(int rowIndex) {
            int ix = Collections.binarySearch(hidden, rowIndex);
            if (ix > -1) {
                return -1;
            }
            int modelIndex = rowIndex + (-ix-1);
            hidden.add(modelIndex);
            fireTableRowsDeleted(rowIndex, rowIndex);
            return modelIndex;
        }

        public void show(int modelIndex) {
            int ix = Collections.binarySearch(hidden, modelIndex);
            if (ix < 0) {
                return;
            }
            hidden.remove(ix);
            int rowIndex = rowIndex(modelIndex);
            fireTableRowsInserted(rowIndex, rowIndex);
        }

        @Override
        public Class<?> getColumnClass(int col) {
            return model.getColumnClass(col);
        }
        @Override
        public int getColumnCount() { return model.getColumnCount(); }

        @Override
        public String getColumnName(int col) {
            return model.getColumnName(col);
        }
        @Override
        public boolean isCellEditable(int row, int col) {
            return model.isCellEditable(row, col);
        }
        @Override
        public int getRowCount() {
            return model.getRowCount() - hidden.size();
        }

        @Override
        public Object getValueAt(int row, int col) {
            return model.getValueAt(modelIndex(row), col);
        }

        @Override
        public void setValueAt(Object value, int row, int col) {
            model.setValueAt(value, modelIndex(row), col);
        }
    }

    public void run() {
        RowFilter filter = new RowFilter(new PersonTable());
        JTable table = new JTable(filter);
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.add(new JScrollPane(table));
        frame.setSize(800, 600);
        frame.setVisible(true);
        new Thread(() -> {
            try{Thread.sleep(2000);} catch (InterruptedException ex) {}
            SwingUtilities.invokeLater(() -> filter.hide(4));
            try{Thread.sleep(2000);} catch (InterruptedException ex) {}
            SwingUtilities.invokeLater(() -> filter.show(4));
        }).start();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new Test().run());
    }
}
 
Passende Stellenanzeigen aus deiner Region:

Neue Themen

Oben