Erklärung gesucht - Verhalten bei JTree/DefaultMutableNode + ToolTip

windhouse

Grünschnabel
Servus zusammen,

ich habe ein kurioses Verhalten festgestellt und kann mir dieses nicht erklären. Ich hoffe, jemand von euch hat eine Idee und kann mir so den Sachverhalt, bzw. meinen Fehler aufzeigen.

Zur Ausgangssituation:
Mein Programm erstellt einen JTree. Die einzelnen Knoten werden mittels einen überschriebenen DefaultTreeCellRenderer angepasst.
Code:
...
    public Component getTreeCellRendererComponent(
                        JTree tree,
                        Object value,
                        boolean sel,
                        boolean expanded,
                        boolean leaf,
                        int row,
                        boolean hasFocus) {
    	/* Die zurückgelieferte Komponente, wird ein JPanel sein */
    	JPanel p = new JPanel(new BorderLayout());
    	
        /* Definiere das Label mit dem entsprechenden Inhalt
         *  - Das Label hat ggf. einen ToolTip (interessant für das spätere Problem)*/
    	InventoryTreeLabel label = new InventoryTreeLabel(
        		(DefaultMutableTreeNode)value,
        		this.useCode555Highlighting,
        		expanded);
    	/* Setze entsprechende dem Fokus und der Selektion das Highlighting */
        if(hasFocus || sel)
        	label.highlight4Focus();
        
        /* Label dem Panel anfügen */
        p.add(label, BorderLayout.CENTER);
        
        /* Handelt es sich bei dem beinhalteten Wert des Knotens um 
         * ein InventoryPeripherieDO, prüfe, ob Historiendaten vorliegen */
        if(((DefaultMutableTreeNode)value).getUserObject() instanceof InventoryPeripherieDO
        		&& ((InventoryPeripherieDO)((DefaultMutableTreeNode)value).getUserObject()).hasHistory()
        		){
        	final InventoryPeripherieDO _invDO = ((InventoryPeripherieDO)((DefaultMutableTreeNode)value).getUserObject());
        	
        	/* Füge einen Button zum Aufruf der Historiendaten an */
        	final JButton callHistory = new JButton(){
				private static final long serialVersionUID = 1L;
				
				@Override
				public Dimension getPreferredSize(){
					return new Dimension(20,18);
				}
        	};
        	callHistory.setBorder(BorderFactory.createEmptyBorder(0,2,0,0));
        	callHistory.setIcon(SupportTOOL.getImageIcon("book_blue_open2"));
        	callHistory.setBackground(DialogTools.getDefaultBackgroundColor());
        	callHistory.setToolTipText("Historie zu diesem CI-Typen anzeigen");
        	callHistory.addActionListener(new ActionListener() {
				
				@Override
				public void actionPerformed(ActionEvent arg0) {
		    		InventoryPeripherieHistoryPopupMenu popUp = _invDO.getHistoryPopup();
		    		popUp.show(callHistory, callHistory.getLocationOnScreen().x, 250);

				}
			});
            p.add(callHistory, BorderLayout.EAST);

        }
        return p;
    }
...

Da ich, wie zu sehen ist, ggf. Buttons mit in dem Panel verwende, und diese direkt ansteuern möchte, versetze ich den Knoten direkt in den Editiermodus, sobald die Maus sich über diesem befindet. Somit kann der Button direkt angewählt werden, ohne vorher den lästigen "einmal klicken für Editormodus" verwenden zu müssen. Der Expand und Collapse via Doppelklick wird hierdurch nicht beeinflusst.

Code:
...
					@Override
					public void mouseMoved(MouseEvent e) {
				        inventoryTree.startEditingAtPath(inventoryTree.getPathForLocation(e.getX(), e.getY()));
				    }

...

Hier nun noch der Editor:
Code:
...
	@Override
	public Component getTreeCellEditorComponent(JTree tree,
            Object value,
            boolean isSelected,
            boolean expanded,
            boolean leaf,
            int row){
		System.out.println("Editing started for row " + row);
		return tree.getCellRenderer().getTreeCellRendererComponent(tree, value, isSelected, expanded, leaf, row, true);
	}
...

Das funktioniert soweit alles auch ganz wunderbar. ABER!
Sobald das Label, welches im TreeCellRenderer erstellt wird, einen ToolTip mitbekommt, funktioniert der Expand/Collapse auf diesem Knoten nicht mehr. Nehme ich den ToolTip raus, läuft alles ganz wunderbar.

Ich kann mir dieses Verhalten nicht erklären. Vielleicht mache ich auch noch etwas falsch oder/und ich bin blind für den eigenen Sourcecode geworden...

Hoffe einer von euch hat eine Idee/Erklärung.

Besten Dank schonmal!
 
Da ich, wie zu sehen ist, ggf. Buttons mit in dem Panel verwende, und diese direkt ansteuern möchte, versetze ich den Knoten direkt in den Editiermodus, sobald die Maus sich über diesem befindet.
Klingt als wäre genau das dein Problem. Probier mal ob es funktioniert, wenn du den Knoten erst auf Klick (ActionListener oder so was) in den Editiermodus versetzt.
Prinzipiell klingt das aber nach einem JRE Bug.
 
Vielen Dank für den Denkanstoss.
Die Ursache ist nicht, dass die Zelle (bzw. der Baumknoten) auf editierbar gesetzt wird, sondern der ToolTip selbst am Label. Es handelt sich nicht um einen Bug in der JRE, sondern lediglich um einen Sachverhalt, den man erstmal wissen und verstehen muss...

Wird einem Element ein ToolTip angefügt, wird das Element mit einem MouseMotionListener versehen. Ab hier ist eine tiefere Beschäftigung mit der Verarbeitung der Events bei den Labels ratsam. Folgende Seiten kann ich empfehlen - Stichwort "transparancy":
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4413412
http://download.java.net/javadesktop/blogs/alexfromsun/2006.06.28/BOF-0204.pdf (Abschnitt MouseEvents!)

Kruze Zusammenfassung (Sollte ich etwas falsch verstanden haben, korrigiert mich bitte!):
Das folgende Beispiel arbeitet korrekt. Auch beim anklicken des Labels, wird "MouseClicked" in der Konsole aufgeführt.
Java:
MouseAdapter ma = new MouseAdapter() {
  public void mouseClicked(MouseEvent e) {
    System.out.println("MouseClicked");
  }
};
frame.addMouseListener(ma);
JLabel label = new JLabel("Label");
// MouseEvents go through the label
frame.add(label);

Im folgenden Beispiel hingegen, führt der ToolTip (und der damit verbundene MouseMotionListener) dafür, dass das Label seine "transparenz" verliert und das Event nicht an den Frame weitergereicht wird. Klickt man in den Frame, wird "MouseClicked" somit in der Konsole angefügt. Klickt man auf das Label, geschieht nichts.
Java:
MouseAdapter ma = new MouseAdapter() {
  public void mouseClicked(MouseEvent e) {
    System.out.println("MouseClicked");
  }
};
frame.addMouseListener(ma);
JLabel label = new JLabel("Label");
// it breaks transparency
label.setToolTipText("Hello");
frame.add(label);

Für meinen Fall bedeutete dies, dass ich alle Label mit einem MouseAdapter versehen habe (nur um sicherzustellen, dass ich einen einheitlichen Weg für alle Label gehe), welcher das MouseClicked-Event behandelt und an meinen Tree weiterreicht. Hierfür muss die Tree-Klasse von JTree abgeleitet werden, um die protected processMouseEvent-Methode ansteuern zu können. Mein Problem ist hiermit behoben. Hoffe mit dieser Erklärung auch anderen helfen zu können.

Beste Grüße,
Flo
 
Danke das du dir die Mühe gemacht hast es so ausführlich zu erklären. So haben hoffentlich auch in Zukunft weitere User Zugriff auf diese Information falls sie ein ähnliches Problem bekommen.
Ich habe mir das schon gedacht das es da Probleme zwischen deinem MouseListener und dem für das ToolTip gibt ... aber das das so tief geht hätte ich dann doch nicht gedacht.
 
Zurück