Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
So also, ich frag jetzt einfach mal ins Blaue hinein, weil ich weiß echt nicht was ich euch an Code zeigen sollte. Mein Problem: Wenn beim Klick auf den Table-Header (auf eine Spalte) die SortKeys geändert werden, passiert es manchmal dass eine Spalte 1px breiter oder schmäler wird..
Das beobachte ich bisher nur, wenn man den Columns eine preferredSize vergeben hat (die nicht bei allen gleich ist). Also hier ne Demo von dem Verhalten:
Java:
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableRowSorter;
public class JTableColumnResizeOnClick extends JFrame {
public static void main(String[] args) {
new JTableColumnResizeOnClick().setVisible(true);
}
public JTableColumnResizeOnClick() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
MyModel model = new MyModel();
JTable table = new JTable(model);
/* set table column widths */
for (int i = 0; i < table.getColumnCount(); i++) {
TableColumn col = table.getColumnModel().getColumn(i);
int width = 26 + (int)(Math.random()*50);
int min = 25;
col.setPreferredWidth(width);
col.setMinWidth(min);
}
table.setRowSorter(new TableRowSorter<MyModel>(model));
add(new JScrollPane(table));
pack();
}
class MyModel extends AbstractTableModel {
@Override
public int getColumnCount() {
return 6;
}
@Override
public int getRowCount() {
return 10;
}
@Override
public Class<?> getColumnClass(int arg0) {
return String.class;
}
@Override
public String getColumnName(int column) {
return "col";
}
@Override
public Object getValueAt(int arg0, int arg1) {
return "Cell";
}
}
}
Klickt mal in den Spalten-Headern rum, vertauscht Spalten usw. Es sollte irgendwann auffallen, dass eben manchmal eine Spalte ihre größe leicht ändert. Ich denke es ist echt nur 1px.
Also mein wirkliches Problem ist folgendes: Ich hab ne App mit nem Table, bei dem so ziemlich alles "custom" ist. D.h. eigener Header-Renderer, Header-Listener usw. Auch dort setz ich wie im Code oben die Sizes für meine Spalten. Aber dort passiert es mir nicht, dass sie ihre Größe verändern.
Ich hab eig. schon alles so nachgebaut gehabt wie in der anderen App, und trotzdem hab ich bei meiner neuen App noch immer dieses Problem. Also irgendwas übersehe ich.
Jetzt also einfach mal ne Frage, ob einer von euch weiß woran das liegt, also wer oder was ist zuständig für diese Veränderung der Größe beim Ändern der SortKeys?
Ich sehe das Phänomen :bae:. Es scheint von den relativen Spaltenbreiten abzuhängen. Dein Testprogramm legt die Spaltenbreiten ja zufällig fest und so kam es bei mir zu einem Fall, wo ich das Programm startete ohne dass danach der Fehler auch nur ein einziges mal auftrat. Darum halte ich das Ganze für einen Rundungsfehler im Autoresize.
Also ich konnte das Problem jetzt beheben, und zwar hat das was mit der ScrollPane zu tun. (@André: Aber wohl auch was mit den Sizes der Spalten) Ich berechne die Größe der ScrollPane indem ich die preferredSizes der Columns zusammenrechne, und dann auch noch die Breite der ScrollBar (die ich immer anzeige) hinzuaddiere. Hier meine Klasse:
Java:
public class TableScrollPane extends JScrollPane {
public TableScrollPane(MyTable table) {
super(table);
setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
// calculate width from table column widths & width of scroll bar
int width = 0;
for (int i = 0; i < table.getColumnCount(); i++) {
TableColumn col = table.getColumnModel().getColumn(i);
width += col.getPreferredWidth();
}
width += getVerticalScrollBar().getPreferredSize().width;
width -= 1; // ????????????
// set a height where cells are fully visible, and not cut off
int cellsToDisplay = 20;
int headerHeight = table.getTableHeader().getPreferredSize().height;
int height = headerHeight + (cellsToDisplay * table.getRowHeight());
// set size
setPreferredSize(new Dimension(width, height));
}
}
Der Schlüssel war die Zeile
Java:
width -= 1; // ????????????
. Wenn ich das tue tritt der Fehler nicht auf. Aber zwei Dinge verstehe ich nicht
1) WARUM? Hab ich hier nen Logik-Fehler? Die SP ist doch so breit wie alle Spalten und die ScrollBar oder?
2) Bei zwei Spalten liest er mir übrigens oben in der Schleife nicht die Werte aus, die ich vorher im Table gesetzt habe. Aus 75/bzw 70 hat er 80 gemacht. Die anderen stimmen...
Ich melde mich nochmal. Inzwischen hat sich auch mein TableHeader wieder verändert, und nun stimmt auch nicht mal mehr die Höhe vom ScrollPane Ich weiss einfach nicht, was ich hier noch vergesse...
Also nochmal meine JScrollPane-Klasse:
Java:
public TableScrollPane(MyTable table) {
super(table);
setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
// install table settings button
TableSettings settings = new TableSettings(table);
setCorner(ScrollPaneConstants.UPPER_RIGHT_CORNER, settings);
// calculate width from table column widths & width of scroll bar
int width = 0;
for (int i = 0; i < table.getColumnCount(); i++) {
TableColumn col = table.getColumnModel().getColumn(i);
width += col.getPreferredWidth();
}
width += getVerticalScrollBar().getPreferredSize().width;
width -= 1; // ????????????
// set a height where all cells are fully visible
int cellsToDisplay = 20;
int headerHeight = table.getTableHeader().getPreferredSize().height;
int cornerHeight = getCorner(ScrollPaneConstants.UPPER_RIGHT_CORNER)
.getPreferredSize().height;
int maxHeight = Math.max(headerHeight, cornerHeight);
int height = maxHeight + (cellsToDisplay * table.getRowHeight());
height += 2; // ????????????
// set size
setPreferredSize(new Dimension(width, height));
}
Die mit ??????? markierten Zeilen lösen das Problem, aber ich weiss nicht wieso:
zum width-1: Optisch sieht man da gar keinen Unterschied, weil ich ja nicht mit dem bloßen Auge sagen kann ob die Pane nun 1px weniger breit ist oder nicht.
Aber das löst das weiter oben genannte Problem mit diesem Column-Resize, also soweit nix "neues"
zum height+2: Das ist neu, und das musste ich einbauen nachdem ich meinen TableHeaderRenderer verändert hab. Auf Grund neuer Komponenten ist er nun höher geworden (Es ist ein JPanel mit BorderLayout). Die Berechnung sollte meines Wissens nach in einer Höhe resultieren, wo das ScrollPane den Header anzeigt sowie 20 Zeilen, und zwar exakt. D.h. keine abgeschnittenen Zeilen, sondern so dass es genau aufgeht.
Zu dem Corner: Ich hab da nen Button drin, und entweder der Button richtet sich nach der Höhe des Headers aus oder andersrum, je nachdem was höher ist. Deshalb also diese Prüfung. (Der Header ist übrigens in diesem Fall grösser).
Nun also.. ich verstehe einfach nicht wieso das nicht alles schön aufgeht. Ich hab auch nach Insets gesucht usw, aber alles was ich mir da ausgegeben hab war eh 0.
Ich würd mich echt sehr freuen wenn mich da mal jmd aufklärt :toll:
PS: eigentlich, so zumindest finde ich es logisch, hätte ich bei der Berechnung der width auch - ähnlich wie bei der height - erstmal prüfen müssen ob die vertikale ScrollBar breiter ist oder die Corner, und das Maximum nehmen. Aber irgendwie bekomme ich bei der preferredWidth der corner einen Wert von "46", obwohl das Ding in der Anzeige nur so breit ist wie die ScrollBar. (Und das sind nur 15 oder 20)
Da keiner antwortet versuch ich's nochmal mit einer Demo. Einfach starten und über folgendes nachdenken:
1) Wieso wird die unterste sichtbare Zelle des Tables nicht voll angezeigt (siehe height-Berechnung des ScrollPanes)?
2) Wieso ändern manchmal Columns ihre Breite (1px) wenn man sie rumschiebt und drauf rumklickt? Und wieso wird dieses Problem behoben, wenn man an der width-Berechnung des ScrollPanes ein wenig rumspielt, zB am Ende 2px abziehen oder ähnliche Magic-Numbers.
Danke euch, das Problem will ich echt gelöst bekommen weil es nervt mich dass ich scheinbar nicht verstehe wie der LayoutManager die Größen berechnet!
KSKB:
Java:
import java.awt.Dimension;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.TableColumn;
public class ScrollPaneTest extends JFrame {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new ScrollPaneTest().setVisible(true);
}
});
}
public ScrollPaneTest() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
// add a scroll pane with a table
add(createScrollPane(createTable()));
pack();
setLocationRelativeTo(null);
}
private JTable createTable() {
JTable table = new JTable(50, 5);
table.setAutoCreateRowSorter(true);
/* set column widths */
for (int i = 0; i < table.getColumnCount(); i++) {
TableColumn col = table.getColumnModel().getColumn(i);
int pref = 0;
switch (i) {
case 0:
pref = 400;
break;
case 1:
pref = 75;
break;
case 2:
pref = 150;
break;
case 3:
pref = 100;
break;
case 4:
pref = 70;
break;
case 5:
pref = 100;
break;
}
col.setPreferredWidth(pref);
}
table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
return table;
}
private JScrollPane createScrollPane(JTable table) {
JScrollPane sp = new JScrollPane(table);
sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
/*
* calculate proper width & height. If we skip this, and let the scroll
* pane pack itself automatically, the scroll pane packs the table
* smaller than it should be according to the set column widths..
* (Because we did not set AUTO_RESIZE_OFF, and don't want that!) So we
* calculate it manually:
*/
int width = 0;
for (int i = 0; i < table.getColumnCount(); i++) {
TableColumn col = table.getColumnModel().getColumn(i);
width += col.getPreferredWidth();
}
width += sp.getVerticalScrollBar().getPreferredSize().width;
// set a height where no cell is cut off.
int cellsToDisplay = 20;
int headerHeight = table.getTableHeader().getPreferredSize().height;
int height = headerHeight + (cellsToDisplay * table.getRowHeight());
sp.setPreferredSize(new Dimension(width, height));
return sp;
}
}