DefaultTableModel / JTable sortieren

Hi Tom und alle Anderen,

ich habe mir dein SortierTableModel mal zunutze gemacht. Funktioniert auch, solange ich die Spalten der Tabelle nicht verschiebe. Gibt es die Möglichkeit dies zu lösen auch wenn die Spalten nun verschoben werden. (Er sortiert zwar, aber leider immer nur die Spalte die ursprünglich an der Position lag)

Wäre es desweiteren auch möglich wie in Windows die Spalten erst dann zu sortieren wenn ich auch wirklich direkt darauf klicke. Sprich nicht die Spalte verschieben, bzw. deren Größe verändern möchte.

Hier mal mein Model incl. Panel etc. (AbsoluteLayout.jar sollte vorhanden sein)

Code:
package ecobill.module.base.ui.component;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jdesktop.layout.GroupLayout;
import org.jdesktop.layout.LayoutStyle;

import javax.swing.*;
import javax.swing.event.TableModelListener;
import javax.swing.border.Border;
import javax.swing.table.*;

import ecobill.core.util.I18NItem;
import ecobill.core.util.IdKeyItem;
import ecobill.core.util.IdValueItem;
import ecobill.core.system.Internationalization;
import ecobill.module.base.service.BaseService;

import java.util.Vector;
import java.util.Collection;
import java.util.Comparator;
import java.util.Collections;
import java.awt.*;
import java.awt.event.KeyListener;
import java.awt.event.MouseListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.*;

import com.sun.java.swing.plaf.motif.MotifGraphicsUtils;

/**
 * Das <code>AbstractTablePanel</code> ist eine abstrakte Klasse um auf einfache Art und Weise
 * Tabellen für EcoBill zu erstellen.
 * <p/>
 * User: Romsl
 * Date: 02.10.2005
 * Time: 12:33:23
 *
 * @author Romsl
 * @version $Id: AbstractTablePanel.java,v 1.11 2005/11/08 18:09:35 romsl Exp $
 * @since EcoBill 1.0
 */
public abstract class AbstractTablePanel extends JPanel implements Internationalization {

    /**
     * In diesem <code>Log</code> können Fehler, Info oder sonstige Ausgaben erfolgen.
     * Diese Ausgaben können in einem separaten File spezifiziert werden.
     */
    protected final Log LOG = LogFactory.getLog(getClass());

    /**
     * Das Icon für die aufsteigend sortierte Tabelle.
     */
    private final ImageIcon UP_ICON = new ImageIcon(MotifGraphicsUtils.class
            .getResource("icons/ScrollUpArrow.gif"));

    /**
     * Das Icon für die absteigend sortierte Tabelle.
     */
    private final ImageIcon DOWN_ICON = new ImageIcon(MotifGraphicsUtils.class
            .getResource("icons/ScrollDownArrow.gif"));

    /**
     * Der <code>Border</code> der um das gesamte <code>JPanel</code> gelegt wird.
     */
    private Border panelBorder;

    /**
     * Gibt den <code>Border</code>, der um das gesamte <code>JPanel</code> gelegt wird, zurück.
     *
     * @return Der <code>Border</code> der um das gesamte <code>JPanel</code> gelegt wird.
     */
    public Border getPanelBorder() {
        return panelBorder;
    }

    /**
     * Die Reihenfolge wie die Spalten angezeigt werden, sofern das <code>TableColumnModel</code>
     * noch nicht serialisiert wurde.
     */
    private Vector<I18NItem> tableColumnOrder;

    /**
     * Gibt die Reihenfolge wie die Spalten angezeigt werden sollen, zurück.
     *
     * @return Die Reihenfolge wie die Spalten angezeigt werden sollen.
     */
    public Vector<I18NItem> getTableColumnOrder() {
        return tableColumnOrder;
    }

    /**
     * Das <code>TableModel</code> beinhaltet die eigentlichen Daten, die zur Anzeige verwendet werden
     * sollen.
     */
    private SortableTableModel tableModel = new SortableTableModel();

    public class SortableTableModel extends DefaultTableModel {

        private boolean sortColumnDesc;

        private int currentSortColumn = 0;

        public int getCurrentSortColumn() {
            return currentSortColumn;
        }

        public SortableTableModel() {
            super();
            sortColumnDesc = true;
        }

        private Comparator comparator = new Comparator() {
            public int compare(Object o1, Object o2) {
                Vector v1 = (Vector) o1;
                Vector v2 = (Vector) o2;

                int size1 = v1.size();
                if (currentSortColumn >= size1)
                    throw new IllegalArgumentException("max column idx: "
                                                       + size1);

                System.out.println("CURR_COL: " + currentSortColumn);

                Comparable c1 = (Comparable) v1.get(currentSortColumn);
                Comparable c2 = (Comparable) v2.get(currentSortColumn);

                System.out.println("C1: " + c1);
                System.out.println("C2: " + c2);

                int cmp = -1;
                if (c1 != null) {
                    cmp = c1.compareTo(c2);
                }

                if (sortColumnDesc) {
                    cmp *= -1;
                }

                return cmp;
            }
        };

        public void sortByColumn(final int clm) {

            Vector v = AbstractTablePanel.this.getTableModel().getDataVector();

            System.out.println("V: " + v);

            this.currentSortColumn = clm;

            Collections.sort(v, comparator);


            if (clm != currentSortColumn) {
                this.sortColumnDesc = true;
            }
            else {
                this.sortColumnDesc ^= true;
            }
        }

        /**
         * @see DefaultTableModel#getColumnClass(int)
         */
        public Class<?> getColumnClass(int columnIndex) {
            try {
                return getValueAt(0, columnIndex).getClass();
            }
            catch (Exception e) {
                return super.getColumnClass(columnIndex);
            }
        }
    }

    private boolean filteredModelInUse;

    public boolean isFilteredModelVisible() {
        return filteredModelInUse;
    }

    /**
     * Gibt das <code>TableModel</code> der Tabelle zurück.
     *
     * @return Das <code>TableModel</code> der Tabelle.
     */
    public SortableTableModel getTableModel() {
        return tableModel;
    }

    /**
     * Die eigentliche <code>JTable</code> mit ihrem <code>TableModel</code>.
     */
    private JTable table = new JTable(getTableModel());

    /**
     * Gibt die eigentliche <code>JTable</code> mit ihrem <code>TableModel</code>, zurück.
     *
     * @return Die eigentliche <code>JTable</code> mit ihrem <code>TableModel</code>.
     */
    public JTable getTable() {
        return table;
    }

    /**
     * Eine <code>JScrollPane</code> um zu ermöglichen, dass die Tabelle gescrollt werden kann und der
     * Tabellen Header angezeigt wird.
     */
    private JScrollPane tableSP = new JScrollPane();

    /**
     * Die <code>JComboBox</code> enthält die möglichen Filterfelder.
     */
    private JComboBox filterBox = new JComboBox();

    /**
     * Das <code>JTextField</code> enthält den zu suchenden Text.
     */
    private JTextField filterField = new JTextField();

    /**
     * Das <code>JPopupMenu</code> das auf reagieren der rechten Maustaste eingerichtet wird.
     */
    private JPopupMenu popupMenu = new JPopupMenu();

    /**
     * Gibt das <code>JPopupMenu</code> zurück, das auf reagieren der rechten Maustaste eingerichtet
     * ist.
     *
     * @return Das <code>JPopupMenu</code> reagiert auf die rechte Maustaste.
     */
    public JPopupMenu getPopupMenu() {
        return popupMenu;
    }

    /**
     * Gibt die <code>JScrollPane</code> zurück, in der die Tabelle liegt. Diese <code>JScrollPane</code>
     * ist nötig um den Tabellen Header anzuzeigen und auch um die Tabelle scrollbar zu gestallten.
     *
     * @return Die <code>JScrollPane</code>, in der die Tabelle liegt.
     */
    public JScrollPane getTableSP() {
        return tableSP;
    }

    /**
     * Der <code>BaseService</code> ist die Business Logik. Unter anderem können hierdurch Daten
     * aus der Datenbank ausgelesen und gespeichert werden.
     */
    private BaseService baseService;

    /**
     * Gibt den <code>BaseService</code> und somit die Business Logik zurück.
     *
     * @return Der <code>BaseService</code>.
     */
    public BaseService getBaseService() {
        return baseService;
    }

    /**
     * Setzt den <code>BaseService</code> der die komplette Business Logik enthält
     * um bspw Daten aus der Datenbank zu laden und dorthin auch wieder abzulegen.
     *
     * @param baseService Der <code>BaseService</code>.
     */
    public void setBaseService(BaseService baseService) {
        this.baseService = baseService;
    }

    protected AbstractTablePanel(BaseService baseService) {

        if (LOG.isDebugEnabled()) {
            LOG.debug("Erzeuge TablePanel.");
        }

        // Der <code>BaseService</code> um den Zugriff auf die Datenbank zu ermöglichen.
        this.baseService = baseService;

        // Erzeugt den Panel <code>Border</code> und setzt die Reihenfolge der Spalten.
        panelBorder = createPanelBorder();
        tableColumnOrder = createTableColumnOrder();

        // Initialisieren der Komponenten und des Layouts.
        initComponents();
        initLayout();

        // Fügt der <code>JTable</code> und dem <code>TableModel</code> die Listener hinzu.
        addKeyListeners(createKeyListeners());
        addMouseListeners(createMouseListeners());
        addTableModelListeners(createTableModelListeners());

        // Füge das <code>JPopupMenu</code> nur hinzu wenn es gebraucht wird.
        if ((popupMenu = createPopupMenu(popupMenu)) != null) {
            initPopupMenu();
            table.add(popupMenu);
        }

        // Erstes initialisieren der Labels, etc...
        reinitI18N();

        // Setzt die Reihenfolge der Spalten.
        tableModel.setColumnIdentifiers(getTableColumnOrder());

        // Dieser renew wird ausgeführt um die Tabelle beim ersten Laden mit Daten zu
        // füllen.
        renewTableModel();

        // Ruft die Methode auch beim ersten Start um das <code>TableColumnModel</code> zu
        // initialisieren.
        createEditoredColumnModelAfterUnpersist(table.getColumnModel());

        table.getTableHeader().setDefaultRenderer(
                new DefaultTableCellRenderer() {

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

                        JTableHeader header = table.getTableHeader();
                        setForeground(header.getForeground());
                        setBackground(header.getBackground());
                        setFont(header.getFont());

                        setText(value == null ? "" : value.toString());
                        setBorder(UIManager.getBorder("TableHeader.cellBorder"));
                        //setHorizontalAlignment(SwingConstants.CENTER);
                        setHorizontalTextPosition(SwingConstants.LEFT);

                        //if (tableModel.sortColumnDesc[column]) {
                        if (AbstractTablePanel.this.getTableModel().getCurrentSortColumn() == column) {
                            if (tableModel.sortColumnDesc) {
                                setIcon(UP_ICON);
                            }
                            else {
                                setIcon(DOWN_ICON);
                            }
                        }
                        else {
                            setIcon(null);
                        }

                        return this;
                    }
                });

        table.getTableHeader().addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent evt) {
                tableModel.sortByColumn(table.columnAtPoint(evt.getPoint()));
            }
        });
    }

    /**
     * Initialisiert die Komponenten.
     */
    private void initComponents() {

        setBorder(panelBorder);

        tableSP.setViewportView(table);
        tableSP.getViewport().setBackground(Color.WHITE);
        table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

        // Schaltet das Tabellengitter aus.
        table.setShowGrid(false);
    }

    /**
     * Initialisiert den <code>LayoutManager</code>.
     */
    private void initLayout() {

        GroupLayout layout = new GroupLayout(this);

        setLayout(layout);

        layout.setHorizontalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
                .addContainerGap()
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING)
                    .add(org.jdesktop.layout.GroupLayout.LEADING, tableSP, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 439, Short.MAX_VALUE)
                    .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
                        .add(filterBox, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 152, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(filterField, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 281, Short.MAX_VALUE)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(org.jdesktop.layout.GroupLayout.LEADING, layout.createSequentialGroup()
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING, false)
                    .add(filterBox)
                    .add(org.jdesktop.layout.GroupLayout.LEADING, filterField))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(tableSP, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 212, Short.MAX_VALUE)
                .addContainerGap())
        );
    }

    /**
     * Initialisieren des <code>JPopupMenu</code>. Hier wird der Klick der rechten Maustaste
     * hinzugefügt.
     */
    private void initPopupMenu() {

        // Vorbereiten der <code>JTable</code> auf das <code>JPopupMenu</code>.
        table.addMouseListener(new MouseAdapter() {

            /**
             * @see MouseAdapter#mousePressed(java.awt.event.MouseEvent)
             */
            public void mousePressed(MouseEvent e) {

                // Überprüfe of die rechte Maustaste gedrückt wurde um die
                // Reihe zu markieren.
                if (SwingUtilities.isRightMouseButton(e)) {

                    // Der Punkt an dem gedrückt wurde.
                    Point p = e.getPoint();

                    // Die Reihe in der Tabelle, auf die gedrückt wurde.
                    int row = table.rowAtPoint(p);

                    // Setze die Reihe markiert.
                    table.addRowSelectionInterval(row, row);
                }

                // Zeige das <code>JPopupMenu</code> an.
                if (e.isPopupTrigger()) {
                    popupMenu.show(table, e.getX(), e.getY());
                }
            }

            /**
             * @see MouseAdapter#mouseReleased(java.awt.event.MouseEvent)
             */
            public void mouseReleased(MouseEvent e) {

                // Zeige das <code>JPopupMenu</code> an.
                if (e.isPopupTrigger()) {
                    popupMenu.show(table, e.getX(), e.getY());
                }
            }
        });
    }

    /**
     * Fügt der Tabelle alle <code>KeyListener</code> aus diesem Array hinzu.
     *
     * @param keyListeners Ein Array mit <code>KeyListener</code>.
     */
    private void addKeyListeners(KeyListener[] keyListeners) {

        if (keyListeners != null) {
            for (KeyListener keyListener : keyListeners) {
                table.addKeyListener(keyListener);
            }
        }
    }

    /**
     * Fügt der Tabelle alle <code>MouseListener</code> aus diesem Array hinzu.
     *
     * @param mouseListeners Ein Array mit <code>MouseListener</code>.
     */
    private void addMouseListeners(MouseListener[] mouseListeners) {

        if (mouseListeners != null) {
            for (MouseListener mouseListener : mouseListeners) {
                table.addMouseListener(mouseListener);
            }
        }
    }

    /**
     * Fügt der Tabelle alle <code>TableModelListener</code> aus diesem Array hinzu.
     *
     * @param tableModelListeners Ein Array mit <code>TableModelListener</code>.
     */
    private void addTableModelListeners(TableModelListener[] tableModelListeners) {

        if (tableModelListeners != null) {
            for (TableModelListener tableModelListener : tableModelListeners) {
                tableModel.addTableModelListener(tableModelListener);
            }
        }
    }

    /**
     * Erneuert das <code>TableModel</code> und somit die Daten die darin enthalten sind.
     * Es müssen dazu die Methoden {@link this#createLineVector(Object)} und
     * {@link this#getDataCollection()} richtig implementiert werden.
     */
    public void renewTableModel() {
        // Entfernt alle schon vorhandenen Zeilen aus dem <code>TableModel</code>.
        // Dies muss gemacht werden, das sonst alle Einträge die schon vorhanden
        // sind auch nochmal angezeigt werden.
        Vector dataVector = tableModel.getDataVector();
        dataVector.removeAllElements();

        // Holt die in der Methode implementierte <code>Collection</code> um diese
        // später dem <code>TableModel</code> hinzufügen zu können.
        Collection dataCollection = getDataCollection();

        // Iteriert über die <code>Collection</code> und fügt jedes <code>Object</code>
        // als Zeile dem Datenvektor hinzu. Dazu muss die Methode createLineVector(Object)
        // richtig implementiert werden.
        for (Object o : dataCollection) {

            // Fügt den erzeugten <code>Vector</code> als Zeile dem Datenvektor hinzu.
            dataVector.add(createLineVector(o));

        }

        // Zeichnet die Tabelle nach hinzufügen aller Objekte neu.
        table.repaint();
        tableSP.setViewportView(table);
    }

    /**
     * @see ecobill.core.system.Internationalization#reinitI18N()
     */
    public void reinitI18N() {
        tableSP.setViewportView(table);
    }

    /**
     * @see ecobill.core.system.Persistable#persist(java.io.OutputStream)
     */
    public void persist(OutputStream outputStream) {

        try {

            // Entferne alle Editoren, da sonst das <code>TableModel</code> nicht serialisiert
            // werden kann.
            table.removeEditor();

            // Entferne alle Daten aus dem Datenvektor.
            tableModel.getDataVector().removeAllElements();

            // Beugt einer NotSerializableException vor. Der genaue Grund für diese
            // Exception ist nicht bekannt. Es handelt sich hier lediglich um einen Hook.
            TableColumnModel tableColumnModel = table.getColumnModel();
            table.setColumnModel(new DefaultTableColumnModel());

            // Erzeuge einen <code>ObjectOutputStream</code> um das <code>TableModel</code>
            // zu serialisieren. Danach wird das serialisierte <code>Object</code> geschrieben,
            // der <code>ObjectOutputStream</code> geflusht und geschlossen.
            ObjectOutputStream oos = new ObjectOutputStream(outputStream);
            oos.writeObject(tableColumnModel);
            oos.flush();
            oos.close();
        }
        catch (Exception e) {
            if (LOG.isErrorEnabled()) {
                LOG.error(e.getMessage(), e);
            }
        }
    }

    /**
     * @see ecobill.core.system.Persistable#unpersist(java.io.InputStream)
     */
    public void unpersist(InputStream inputStream) {

        // Erzeuge einen <code>ObjectInputStream</code> um das <code>TableModel</code> wieder
        // zu laden, sollte dieses bereits schon persistiert sein.
        ObjectInputStream ois = null;
        try {
            ois = new ObjectInputStream(inputStream);

            // Lade das persistierte <code>TableColumnModel</code>.
            TableColumnModel columnModel = (TableColumnModel) ois.readObject();

            // Abschließend wird das geladene <code>TableColumnModel</code> wieder in der Tabelle
            // gesetzt.
            table.setColumnModel(createEditoredColumnModelAfterUnpersist(columnModel));
        }
        catch (Exception e) {
            if (LOG.isErrorEnabled()) {
                LOG.error(e.getMessage());
            }
        }
        finally {
            if (ois != null) {
                try {
                    ois.close();
                }
                catch (IOException ioe) {
                    if (LOG.isErrorEnabled()) {
                        LOG.error(ioe.getMessage(), ioe);
                    }
                }
            }
        }
    }

    /**
     * Erlaubt es die Reihenfolge der Werte in der Tabelle neu zu setzen.
     *
     * @param tableColumnOrderNew Die neue Tabellen Spalten Reihenfolge.
     */
    public void setTableColumnOrder(Vector<I18NItem> tableColumnOrderNew) {
        tableColumnOrder = tableColumnOrderNew;
    }

    /**
     * Gibt die Id des Selektierten Datensatzes zurück.
     *
     * @return Die Id des aktuell selektierten Datensatzes.
     * @throws IllegalStateException Diese <code>Exception</code> wird geworfen wenn entweder keine
     *                               Reihe ausgewählt ist oder die Tabelle kein Identifier Objekt hat.
     */
    public Long getIdOfSelectedRow() throws IllegalStateException {

        // Die selektierte Reihe.
        int row = table.getSelectedRow();

        if (row < 0) {
            throw new IllegalStateException("Es wurde keine Reihe ausgewählt.");
        }

        // Das aktuell selektierte Identifier Objekt.
        Object o = tableModel.getValueAt(row, 0);

        if (o instanceof IdKeyItem) {
            return ((IdKeyItem) o).getId();
        }
        else if (o instanceof IdValueItem) {
            return ((IdValueItem) o).getId();
        }

        throw new IllegalStateException("Die Tabelle hat kein Identifier Object.");
    }

    /**
     * Diese Methode kann dazu verwendet werden, um dem <code>TableColumnModel</code> nach einem
     * {@link this#unpersist(java.io.InputStream)}, wieder Editoren hinzuzufügen.
     *
     * @param tableColumnModel Das <code>TableColumnModel</code> der Tabelle.
     * @return Das <code>TableColumnModel</code> dem Editoren hinzugefügt worden sein können.
     */
    protected TableColumnModel createEditoredColumnModelAfterUnpersist(TableColumnModel tableColumnModel) {
        return tableColumnModel;
    }

    /**
     * Durch Überschreiben dieser Methode ist es möglich der <code>JTable</code> <code>KeyListener</code>
     * hinzuzufügen.
     *
     * @return Ein Array mit <code>KeyListener</code> die der <code>JTable</code> hinzugefügt
     *         werden sollen.
     */
    protected KeyListener[] createKeyListeners() {
        return null;
    }

    /**
     * Durch Überschreiben dieser Methode ist es möglich der <code>JTable</code> <code>MouseListener</code>
     * hinzuzufügen.
     *
     * @return Ein Array mit <code>MouseListener</code> die der <code>JTable</code> hinzugefügt
     *         werden sollen.
     */
    protected MouseListener[] createMouseListeners() {
        return null;
    }

    /**
     * Durch Überschreiben dieser Methode ist es möglich dem <code>TableModel</code>
     * <code>TableModelListener</code> hinzuzufügen.
     *
     * @return Ein Array mit <code>TableModelListener</code> die dem <code>TableModel</code> hinzugefügt
     *         werden sollen.
     */
    protected TableModelListener[] createTableModelListeners() {
        return null;
    }

    /**
     * Durch überschreiben dieser Methode ist es möglich der <code>JTable</code> ein
     * <code>JPopupMenu</code> hinzuzufügen.
     *
     * @param popupMenu Das <code>JPopupMenu</code> das auf Klick der rechten Maustaste
     *                  bereits reagieren kann.
     * @return Das <code>JPopupMenu</code>, das der <code>JTable</code> hinzugefügt
     *         werden soll.
     */
    protected JPopupMenu createPopupMenu(JPopupMenu popupMenu) {
        return null;
    }

    /**
     * Erzeugt einen <code>Border</code> der um das gesamte <code>JPanel</code> gelegt wird.
     *
     * @return Ein <code>Border</code> der um das <code>JPanel</code> gelegt werden soll.
     */
    protected abstract Border createPanelBorder();

    /**
     * Erzeugt einen <code>Vector</code> mit <code>I18NItem</code> Elementen um die Tabelle
     * beim ersten Anwendungsstart zu initialisieren. Die Reihenfolge der Spalten gleicht
     * der Reihenfolge wie die <code>I18NItem</code> Elemente im <code>Vector</code>
     * stecken.
     *
     * @return Ein <code>Vector</code> mit <code>I18NItem</code> Elementen.
     */
    protected abstract Vector<I18NItem> createTableColumnOrder();

    /**
     * Es wird hier eine <code>Collection</code> zurückgeliefert. Diese <code>Collection</code>
     * enthält <code>Object</code> die später bei {@link this#createLineVector(Object)}
     * ankommen und dort entsprechend behandelt werden können.
     *
     * @return Eine <code>Collection</code> die alle Daten enthält die in der Tabelle angezeigt
     *         werden sollen.
     */
    protected abstract Collection getDataCollection();

    /**
     * Erzeugt einen <code>Vector</code>, der als Zeile in der Tabelle angezeigt wird.
     *
     * @param o Ein <code>Object</code> aus der <code>Collection</code> das bei
     *          {@link this#getDataCollection()} zurückgeliefert wird.
     * @return Der erzeugte <code>Vector</code> wird als Zeilenvektor dem Datenvektor
     *         hinzugefügt.
     */
    protected abstract Vector createLineVector(Object o);
}


Mich würde noch interessieren ob dies ein sauberer Programmierstiel ist und ob man diese Klasse noch ein wenig "refactoren" kann.

Vielen Dank
 
Re: DefaultTableModel

Thomas Darimont, ich finde deine Lösung sehr sehr schön.
Ich wollte dich (oder alle anderen ^^) einmal fragen wie man das so basteln kann, dass wenn ich eine Zeile selectiert habe, diese nach dem Sortieren immer noch selectiert ist.
 
Na ich hab das derzeit so gemacht wie du sagst. Ich habe eine Tabelle wo die ID mit vorhanden ist (unique).
Nach dem umsortieren suche ich dann die Zeile im JTable, wo diese ID dann ist (Position)

Code:
selID = (String)table.getValueAt(table.getSelectedRow(), 0);
...
...
....
model.sortColumnDesc[clm] ^= true;
			
for(int i=0; i<table.getRowCount();i++){
				if(table.getValueAt(i, 0).equals(selID)){
					table.changeSelection(i, 0, false, false);
					break;
				}
			}


Bei einer Tabelle mit rund 10 Datensätzen geht das schon recht fix, wenn ich jedoch 30.000, denke ich wird das schon performance lastiger. Gerade wenn die Anwendung dann auf einem PDA läuft.

Von daher einfach mal die Frage, ob es vielleicht einen besseren Weg gibt als den, den ich verwendet habe.

Gruß Kerwin
 
Hallo!

Bei der Arbeit mit großen Tables (oder allgemein Widgets die Massendaten anzeigen sollen (Trees, Lists)) lohnt es sich vor einer größeren Aktion die grafische Aktualiserung des entsprechenden Widgets für die Dauer der Aktion zu deaktiveren und danach sofort wieder zu aktivieren. Damit hab ich in größeren Client Anwendungen schon einen Performance-Boost von 100% gesehen ;-)

Gruß Tom
 
Danke für die Info :)

Nun habe ich gerade ein anderes Probem bemerkt wie der User Romsl.
Die Sortierfunktion funktioniert ja super, allerdings nur solange bis man die Spalten nicht vertauscht. Der JTable lässt es ja standardmäßig zu, dass zur Laufzeit per Drag&Drop die Spalten getauscht werden können. Danach funtioniert es halt nicht mehr.
Hat dazu jemand schon etwas gefunden?


Zu dem einen Problem vo Romsl:
Wäre es desweiteren auch möglich wie in Windows die Spalten erst dann zu sortieren wenn ich auch wirklich direkt darauf klicke. Sprich nicht die Spalte verschieben, bzw. deren Größe verändern möchte.

Wenn man den MouseListener auf Clicked setzt, dann hat man dieses Problem nicht mehr und kann die Spalten beliebig verschieben/vergrößern etc ohne das die Sortierfunktion anspringt.

Code:
table.getTableHeader().addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent evt) {
					model.sortByColumn(table.columnAtPoint(evt.getPoint()));
			}
		});
 
Zuletzt bearbeitet:
Hallo...

habe da auch mal eine frage. das Sortieren funktioniert soweit nur möchte ich gerne das er den cursor auf den Datensatz legt, der vorher auch angewählt war und nicht auf den der durchs sortieren an diese Position gerückt ist.
Habe es schon mit table.changeSelection probiert nur kennt er die table an keiner stelle an der ich es probiert habe. Hat da jemand eine idee?

nen weiteres problem ist das ich zur navigation 4 Buttons habe(erster Datensatz,Previous,Next,Letzer Datensatz) auf die ich jeweils changeSelection gelegt habe um immer entsprechend zum datensdatz in der JTable die Zeile zu markieren. Zur Anzeige dienen zusätzlich mehrere Textfelder in denen die Daten angezeigt werden wenn ich navigiere oder auf die JTable klicke. Solange ich nicht sortiere funktioniert alles wunderbar. wenn ich aber jetzt zB die zweite Spalte sortiere werden die Datensätze nach dem Alphabet geordnet da es sich dort um Strings handelt. Jetzt funktioniert natürlich die Navigation nicht mehr da er normalerweise bei changeSelection immer eine Zeile weiter bzw zurück springt. Was kann man da machen?

hier mal nen beispiel:

public void jBtnNext_actionPerformed(ActionEvent e) {
try {
if(!ergebnis2.isLast()){
ergebnis2.next();
felderfuellen();
this.jTable1.changeSelection((jTable1.getSelectedRow())+1,(jTable1.getSelectedColumn())+1,false,false);}
}catch (SQLException next) {System.out.println(next.getMessage());}
}
 
Zuletzt bearbeitet:
Schau mal ein paar Beiträge in diesem Thread zurück, da habe ich geschrieben wie man das machen könnte bzgl der Selektierung vorher/nachher. Bei meiner Tabelle ist das so, dass ich eine Spalte habe in der ein Wert steht, der unique ist. Beispiel ID-Spalte.
Nun mache ich in dem Beispiel nichts anderes als zu schauen, welcher Wert ist vorher selektiert und speichere den zwischen. Nach der umsortierung durchsuche ich den JTable nach der ID und markiere ihn dann wieder.

Code:
public void sortByColumn(final int clm) {
	String selID;
	selID = (String)table.getValueAt(table.getSelectedRow(), 0);
	//..
	//..	
	// rest wie gehabt von Thomas
	// ...
	// ..
	model.sortColumnDesc[clm] ^= true; // <-- diese Zeile gibt es schon und danach den neuen Teil einpflanzen

	// neuer Teil
	for(int i=0; i<table.getRowCount();i++){
		if(table.getValueAt(i, 0).equals(selID)){
			table.changeSelection(i, 0, false, false);
			break;
		}
	}
}
 
Vielen Dank...das klappt jetzt soweit! :-) jetzt muss ich mir noch überlegen wie ich von dem punkt an an dem sortiert wurde und der Datensatz selektiert ist mit der Datensatznavigation weitermache. Vorher wars ja einfach..da hab ich mit .next() etc navigiert und beim klick auf die table hab ich die Position ausgelesen und bin mit .absolute() zur entsprechenden Stelle im resultset gesprungen. Das kann ich so ja leider vergessen..
 
Habe noch eine frage....wenn ich die sortierfunktion soweit übernehme gibt er mir beim sortieren der ersten Spalte (Int) sowas in der Art aus:

9
8
7
6
5
4
3
2
10
11
12
1

was muss man da am code ändern das er das richtig sortiert?
 
Zurück