JTable, TableHeader Tooltips
Robert
- java
Hallöle,
ich schon wieder, und schon wieder mit einem Tooltip-Problem.
Diesmal geht es um Tooltips auf den Headern von JTable-Spalten.
Es gelingt mir zwar, einen Tooltip für den kompletten Header zu setzen, aber nicht für einzelne Spalten.
Hier mein Code:
JTable mTable;
//... sonstige Initialisierung (Modell setzen usw.)
mTable.getTableHeader().setToolTipText("Click to sort! (Tooltip per getTableHeader())");
//das hier funktioniert wunderbar - der Tooltip wird angezeigt.
mTable.setTableHeader(
new JTableHeader(mTable.getColumnModel()) //anonyme Ableitung von JTableHeader
{
public String getToolTipText()
{
return "Click to sort! (ToolTip aus new JTableHeader)";
}
public String getToolTipText(MouseEvent e)
{
System.out.println("getToolTipText(MouseEvent)");
int ix = mTable.getColumnModel().getColumnIndexAtX(e.getPoint().x);
int modelIx = mTable.getColumnModel().getColumn(ix).getModelIndex();
return mColumnNames[modelIx];
}
}
);
System.out.println("ToolTip: " + mTable.getTableHeader().getToolTipText());
//hier kommt wunderbar der Tooltip: "Click to sort! (ToolTip aus new JTableHeader)"
Also scheint das setTableHeader() zu funktioneren
Aber wenn ich jetzt mit der Maus über den TableHeader gehe, kommt der andere Tooltip: Click to sort! (Tooltip per getTableHeader())
Was mache ich falsch?
Ich hätte gerne den jeweiligen Spalten-Namen als Tooltip, weil viele Spalten, die in den Daten nur wenige Zeichen haben, zu schmal sind für die Anzeige des vollständigen Namens.
TIA,
cu,
Robert
Hallöle,
Das Problem mit den Tooltips für einzelne Header ist noch nicht gelöst, aber ich hab noch ein weiteres Problem:
Bei Rechtsklick in die Tabelle soll ein Context-Menü erscheinen (das ist kein Problem).
Welche Menüpunkte dort erscheinen, soll aber davon abhängen. was sich in der rechtsgeklickten Zelle befindet.
D.h. ich muß ermitteln, welche Zelle geklickt wurde.
Für die Spalte hab ich den Code schon.
Fehlt "nur" noch der Code für die Zeile.
public void clickEvent(java.awt.event.MouseEvent evt)
{
if (evt.getButton() == evt.BUTTON3)
{
int displayedIx = mTable.getColumnModel().getColumnIndexAtX(evt.getX());
int col = mTable.getColumnModel().getColumn( displayedIx ).getModelIndex();
//in col steht jetzt die korrekte Spalte aus dem TableModel (egal ob die Spalten noch in Original-Anordnung sind oder vertauscht)
int row = 0; //Wie komme ich hier an die geklickte Zeile der Tabelle?
String cellValue = (String) getValueAt(row, col);
//... Context Menu aufbauen ...
}
}
Irgendwie fehlt mir der Ansatzpunkt - JTable ist ja leider nicht symmetrisch bezüglich Zeilen und Spalten, es fehlt getRowModel() und damit auch getRowModel().getRowIndexAtY(int ypos);
TIA,
cu,
Robert
Hallöle, ich schon wieder ...
D.h. ich muß ermitteln, welche Zelle geklickt wurde.
Ich bin zu blind. Bzw. Java manchmal inkonsequent bei der Namensgebung.
int row = mTable.rowAtPoint(event.getPoint());
int col = mTable.columnAtPoint(event.getPoint());
Warum heißen die beiden nicht getRowAtPoint/getColumnAtPoint?
Dann hätt ich sie gleich gefunden, weil ich automatisch das get getippt hatte, bevor ich im NetBeans die Auto-Vervollständigung aufgerufen hab ...
Bleibt aber noch das Tooltip-Problem aus dem ersten Posting des Threads ...
cu,
Robert
Hallo,
Hier mein Code:
JTable mTable;
//... sonstige Initialisierung (Modell setzen usw.)mTable.getTableHeader().setToolTipText("Click to sort! (Tooltip per getTableHeader())");
//das hier funktioniert wunderbar - der Tooltip wird angezeigt.mTable.setTableHeader(
new JTableHeader(mTable.getColumnModel()) //anonyme Ableitung von JTableHeader
{
public String getToolTipText()
{
return "Click to sort! (ToolTip aus new JTableHeader)";
}public String getToolTipText(MouseEvent e)
{
System.out.println("getToolTipText(MouseEvent)");
int ix = mTable.getColumnModel().getColumnIndexAtX(e.getPoint().x);
int modelIx = mTable.getColumnModel().getColumn(ix).getModelIndex();
return mColumnNames[modelIx];
}
}
);System.out.println("ToolTip: " + mTable.getTableHeader().getToolTipText());
//hier kommt wunderbar der Tooltip: "Click to sort! (ToolTip aus new JTableHeader)"Also scheint das setTableHeader() zu funktioneren
Aber wenn ich jetzt mit der Maus über den TableHeader gehe, kommt der andere Tooltip: Click to sort! (Tooltip per getTableHeader())
Was mache ich falsch?
Gute Frage. Der obenstehende Code funktioniert bei mir. Es wird nie
"Click to sort! (ToolTip aus new JTableHeader)", sondern immer nur
der Spaltenname ausgegeben.
Bist du sicher, daß du (oder irgend eine Swing-Klasse) den TableHeader
nicht nochmal überschreibt, nachdem du deine eigene TableHeader-
Implementierung zugewiesen hast?
Gruß
Slyh
Hallöle,
Gute Frage. Der obenstehende Code funktioniert bei mir. Es wird nie
"Click to sort! (ToolTip aus new JTableHeader)", sondern immer nur
der Spaltenname ausgegeben.
Den bekomme ich ja auch nicht - sondern den, den ich direkt per getTableHeader().setToolTipText() angebe ...
Den obigen bekomme ich nur, wenn ich die Funktion "manuell" aufrufe, also nicht durch den Mauszeiger auslöse.
Bist du sicher, daß du (oder irgend eine Swing-Klasse) den TableHeader
nicht nochmal überschreibt, nachdem du deine eigene TableHeader-
Implementierung zugewiesen hast?
Eigentlich schon.
Es gibt nur eine weitere Stelle, an der auf den TableHeader zugegriffen wird - direkt vor obigem Code wird ausgeführt:
mTable.getTableHeader().addMouseListener(
new MouseAdapter()
{
public void mouseClicked(MouseEvent event)
{
int displayedIx = mTable.getColumnModel().getColumnIndexAtX(event.getX());
int col = mTable.getColumnModel().getColumn( displayedIx ).getModelIndex();
columnHeaderClicked(col);
}
}
);
Das seltsame daran ist: die Mausklicks auf den Header funktionieren (columnHeaderClicked wird aufgerufen).
Eigentlich dürfte das ja gar nicht der Fall sein, da ich ja unmittelbar nach dem Setzen des Mauslisteners den TableHeader, für den er gesetzt ist, durch einen ganz anderen ersetze ...
Ich hatte das mit dem Mauslistener auch schon nach dem Setzen des TableHeader stehen, dann klappte das allerdings auch nicht mehr.
Alles sehr seltsam.
Ich hab jetzt mal
System.out.println("TableHeader: " + mTable.getTableHeader());
vor dem Setzen, nach dem Setzen und in columnHeaderClicked ausgegeben:
TableHeader: javax.swing.table.JTableHeader[,0,0,450x20,invalid,alignmentX=null,alignmentY=null,border=,flags=8,maximumSize=,minimumSize=,preferredSize=,draggedDistance=0,reorderingAllowed=true,resizingAllowed=true,updateTableInRealTime=true]
TableHeader: test.robert.LogTableModel$2[,0,0,0x0,invalid,alignmentX=null,alignmentY=null,border=,flags=8,maximumSize=,minimumSize=,preferredSize=,draggedDistance=0,reorderingAllowed=true,resizingAllowed=true,updateTableInRealTime=true]
TableHeader: test.robert.LogTableModel$2[,0,0,0x0,invalid,alignmentX=null,alignmentY=null,border=,flags=8,maximumSize=,minimumSize=,preferredSize=,draggedDistance=0,reorderingAllowed=true,resizingAllowed=true,updateTableInRealTime=true]
Der richtige Header ist also definitiv vorhanden.
Aber es kommt der falsche Tooltip.
Es hilft auch nicht, statt der anonymen Ableitung eine lokale Klasse zu benutzen, oder die Size des Headers zu setzen (der einzige Unterschied neben dem Klassennamen bei der Ausgabe des TableHeaders ...)
Das ist echt seltsam.
Hm - kann es an der JDK-Version liegen?
Übersetzt wird mit 1.4.2 (im NetBeans), laufen lassen hab ich es unter 1.4.2 und 1.4.2_05 (andere hab ich nicht hier)
cu,
Robert
Hallo,
Gute Frage. Der obenstehende Code funktioniert bei mir. Es wird nie
"Click to sort! (ToolTip aus new JTableHeader)", sondern immer nur
der Spaltenname ausgegeben.Den bekomme ich ja auch nicht - sondern den, den ich direkt per getTableHeader().setToolTipText() angebe ...
Ja. Jedenfalls wird bei meinem Mini-Beispielprogramm, das ich mir
auf Basis deines Codes gemacht habe, immer die aktuelle Spaltennummer
im Tooltip ausgegeben.
Den Code meines Programms habe ich unten angehängt.
Den obigen bekomme ich nur, wenn ich die Funktion "manuell" aufrufe, also nicht durch den Mauszeiger auslöse.
OK.
Das seltsame daran ist: die Mausklicks auf den Header funktionieren (columnHeaderClicked wird aufgerufen).
Eigentlich dürfte das ja gar nicht der Fall sein, da ich ja unmittelbar nach dem Setzen des Mauslisteners den TableHeader, für den er gesetzt ist, durch einen ganz anderen ersetze ...
Ja, dürfte eigentlich nicht :)
Ich hatte das mit dem Mauslistener auch schon nach dem Setzen des TableHeader stehen, dann klappte das allerdings auch nicht mehr.
Was dann wiederum falsch ist, weil genau das nämlich klappen sollte.
Alles sehr seltsam.
Stimmt :)
Ich hab jetzt mal
System.out.println("TableHeader: " + mTable.getTableHeader());
vor dem Setzen, nach dem Setzen und in columnHeaderClicked ausgegeben:
[Offensichtlich korrekte Ausgaben gesnippt]
Der richtige Header ist also definitiv vorhanden.
Aber es kommt der falsche Tooltip.
Komisch, das...
Hm - kann es an der JDK-Version liegen?
Wäre einen Gedanken wert. Ist aber nicht sehr wahrscheinlich...
Übersetzt wird mit 1.4.2 (im NetBeans), laufen lassen hab ich es unter 1.4.2 und 1.4.2_05 (andere hab ich nicht hier)
Meiner einer übersetzt mit Eclipse und führt mit 1.4.2_06 aus.
Du solltest übrigens dringend auf 1.4.2_06 updaten, da im 1.4.2_05
ein Sicherheitsloch entdeckt wurde, das dein System beim Surfen
gefährdet.
So richtig viel kann ich dir bei deinem Problem nicht helfen. Dein
Vorgehen scheint korrekt. Mein vergleichbarer Test funktioniert. Deine
Testausgaben scheinen auch das korrekte Ergebnis zu liefern.
Ich vermute, daß du irgendwo in deinem Code noch einen Fehler hast.
Vielleicht weist du den neuen TableHeader irgendwo an eine falsche
Tabelle zu oder so.
Führe einfach mal mein Testprogramm aus. Wenn das funktioniert,
liegt's wohl an deinem Code.
Vielleicht kannst du ja ein bißchen mehr Code posten, wenn du den
Fehler nicht finden solltest.
Gruß
Slyh
Mein (häßlicher) Beispielcode:
public class TableTooltipTest extends JFrame
{
public TableTooltipTest()
{
super("Test");
}
public static void main(String[] args)
{
TableTooltipTest t = new TableTooltipTest();
t.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
t.setSize(600, 600);
Toolkit.getDefaultToolkit().setDynamicLayout(true);
Container content = t.getContentPane();
JTable table = new JTable(new Object[][] {{"0, 0", "1, 0"}, {"0, 1", "1, 1"}}, new Object[] {"eins", "zwei"});
JScrollPane scroller = new JScrollPane(table);
content.add(scroller);
table.setToolTipText("testtext");
table.getTableHeader().setToolTipText("tableheadertext");
table.setTableHeader(
new JTableHeader(table.getColumnModel()) //anonyme Ableitung von JTableHeader
{
public String getToolTipText()
{
return "Click to sort! (ToolTip aus new JTableHeader)";
}
public String getToolTipText(MouseEvent e)
{
System.out.println("getToolTipText(" + e + ")");
int ix = table.getColumnModel().getColumnIndexAtX(e.getPoint().x);
int modelIx = table.getColumnModel().getColumn(ix).getModelIndex();
return "" + modelIx;
}
}
);
t.show();
}
}
Hallöle,
nach langer Forschungsarbeit hab ich die Lösung gefunden!
Netbeans generiert einiges an Code automatisch.
Unter anderem setzt er die JTable in den JScrollPane.
(jScrollpane.setViewportView(jTable)) und macht das ganze sichtbar.
Und das geschah, bevor ich meinen Header gesetzt hab.
Jetzt hab ich NACH dem Setzen des Headers die Tabelle nochmal in das Scrollpane reingesetzt - und siehe da, ich bekam die richtigen Tooltips.
Allerdings funktionierte das Sortieren nicht mehr - logisch, denn der MouseListener war ja auf den alten Header gesetzt ...
Das ließ sich aber durch Setzen des MouseListeners NACH dem Setzen des Headers leicht korrigieren.
Danke für Deine Bemühungen!
Im Unterschied zu Deinem Beispiel ist beim Netbeans-Code die Tabelle samt Scrollpane schon sichtbar, wenn mein Init-Code drankommt. Das Scrollpane (in dem der Header sitzt) bekommt es dann wohl nicht mehr mit, wenn der Header in der Table gesetzt wird - es sei denn, man setzt die Tabelle erneut in das ScrollPane ...
cu,
Robert