Swing Optimale Spaltenbreite auf Doppelklick (JTable)

Status
Nicht offen für weitere Antworten.

KrokoDiehl

Top Contributor
Hallo zusammen.
Ich habe eine JTable und möchte gern die Funktionalität implementieren, dass sich die Spalten automatisch auf die optimale Breite anpassen, wenn man an den Rand des Spaltenkopfes doppelklickt. Ein ähnliches Verhalten kennt man z.B. aus MS Excel oder auch aus Eclipse (und vielen andren GUIs).
Diese automatische Anpassung soll nur erfolgen, wenn man den Resizing-Cursor hat (also am rechten Rand der Spalte).

Ich habe bisher herumprobiert, bin aber auf noch keine zufriedenstellende Lösung gekommen:
Mittels eines MouseListeners am JTableHeader reagiere ich derzeit auf den Doppelklick. Problem ist aber, dass dieser Doppelklick überall wirkt. Ich möchte es aber nur am (rechten) Rand der Spalte haben.

Was mir bisher nur einfällt ist via Mausposition etc. prüfen, ob sich der Cursor in der Nähe des Spaltenendes befindet... aber ich habe das dumpfe Gefühl, dass es auch viel einfacher geht, da es ja fast so etwas wie Standardfunktionalität ist.

Hier ein bisschen Code:
Java:
...
table.getTableHeader().addMouseListener(new ResizeListener(table));
...
@Override
public void mouseClicked(MouseEvent event)
{
    if ( SwingUtilities.isLeftMouseButton(event) && event.getClickCount() == 2 )
    {
        int col = table.columnAtPoint(event.getPoint());
        // hier Abfrage, ob der Cursor am Spaltenrand ist...

        table.resizeColumnToContents(col); // diese Methode habe ich schon und sie geht
    }
}

Also meine Frage: Kennt jemand hierfür einen direkteren / einfacheren Weg?
 
Diese automatische Anpassung soll nur erfolgen, wenn man den Resizing-Cursor hat
Versuch mal den "cursor type" abzufragen (E_RESIZE_CURSOR / W_RESIZE_CURSOR);
Java:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;

public class WidthAdjuster extends MouseAdapter {

    private JTable table;
    private static final int EPSILON = 5;   //boundary sensitivity
    private static final Cursor EAST = Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR);
    private static final Cursor WEST = Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR);

    public WidthAdjuster(final JTable table) {
        this.table = table;
        table.getTableHeader().addMouseListener(this);
    }

    @Override
    public void mousePressed(final MouseEvent evt) {
        if (evt.getClickCount() > 1 && usingResizeCursor()) {
            resize(getLeftColumn(evt.getPoint()));
        }
    }

    private JTableHeader getTableHeader() {
        return table.getTableHeader();
    }

    private boolean usingResizeCursor() {
        Cursor cursor = getTableHeader().getCursor();
        return cursor.equals(EAST) || cursor.equals(WEST);
    }

    //if near the boundary, will choose left column
    private int getLeftColumn(final Point pt) {
        pt.x -= EPSILON;
        return getTableHeader().columnAtPoint(pt);
    }

    private void resize(final int col) {
        TableColumnModel tcm = table.getColumnModel();
        TableColumn tc = tcm.getColumn(col);
        TableCellRenderer tcr = tc.getHeaderRenderer();
        if (tcr == null) {
            tcr = table.getTableHeader().getDefaultRenderer();
        }
        Object obj = tc.getHeaderValue();
        Component comp = tcr.getTableCellRendererComponent(table, obj, false, false, 0, 0);
        int maxWidth = comp.getPreferredSize().width;

        for (int i = 0, ub = table.getRowCount(); i != ub; ++i) {
            tcr = table.getCellRenderer(i, col);
            obj = table.getValueAt(i, col);
            comp = tcr.getTableCellRendererComponent(table, obj, false, false, i, col);
            int w = comp.getPreferredSize().width;
            if (w > maxWidth) {
                maxWidth = w;
            }
        }
        maxWidth += 10; //and room to grow...
        tc.setPreferredWidth(maxWidth); //remembers the value
        tc.setWidth(maxWidth);          //forces layout, repaint
    }

    public static void main(final String[] args) {
        Runnable gui = new Runnable() {

            @Override
            public void run() {
                JFrame f = new JFrame();
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.setSize(400, 300);
                f.setLocationRelativeTo(null);
                JTable table = new JTable(4, 4);
                table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
                f.add(new JScrollPane(table));
                new WidthAdjuster(table);
                f.setVisible(true);
            }
        };
        //GUI must start on EventDispatchThread:
        SwingUtilities.invokeLater(gui);
    }
}
 
Zuletzt bearbeitet:
Stimmt, das ist eine gute Möglichkeit und funktioniert nahezu perfekt. Störend ist noch, dass wenn ein RowSorter gesetzt ist, er die Spalte dann noch sortiert. Ich habe es mit
Code:
event.consume()
versucht aber da die Reihenfolge der MouseListener nicht fix ist, denke ich, wird das etwas umständlicher.
Aber bis dahin reicht das erstmal. Bisher ist es nur eine nice-to-have Funktionalität.
Danke dir.
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben