LayoutManager Null-Layout unter Linux im TreeCellEditor

FerFemNemBem

Bekanntes Mitglied
Mahlzeit,

ich habe einen eigenen TreeCellEditor und einen TreeCellRenderer gebaut, welche die Zellen nach meinen Vorstellungen darstellen. Unter Windows funktioniert das alles einwandfrei. Wenn ich das Programm allerdings auf meinem Linux-Mint laufen lasse, sehe ich die Zellen, die der TreeCellEditor darstellen solll nicht.

Hier mal ein laufendes (zusammengekuerztes) Beispielprogramm:

Java:
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.util.EventObject;

import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.event.CellEditorListener;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeCellEditor;

public class TreeTest 
{
	private JFrame frame;
	private JTree jTree;

	public static void main(String[] args) 
	{
		EventQueue.invokeLater(new Runnable() 
		{
			public void run() 
			{
				try 
				{
					TreeTest window = new TreeTest();
					window.frame.setVisible(true);
				} 
				catch (Exception e) 
				{
					e.printStackTrace();
				}
			}
		});
	}

	public TreeTest()
	{
		frame = new JFrame();
		frame.setBounds(100, 100, 450, 300);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		jTree = new JTree();
		jTree.setEditable(true);
		CheckBoxTreeNodeRenderComponent checkBoxTreeNodeRenderComponent = new CheckBoxTreeNodeRenderComponent();
		TestTreeCellRenderer testTreeCellRenderer = new TestTreeCellRenderer(checkBoxTreeNodeRenderComponent);
		jTree.setCellRenderer(testTreeCellRenderer);
		CheckBoxTreeNodeEditorComponent checkBoxTreeNodeEditorComponent = new CheckBoxTreeNodeEditorComponent();
		TestTreeCellEditor testTreeCellEditor = new TestTreeCellEditor(checkBoxTreeNodeEditorComponent);
		jTree.setCellEditor(testTreeCellEditor);
		frame.add(jTree);
	}

	public class CheckBoxTreeNodeRenderComponent extends JPanel
	{
		JCheckBox checkBox = new JCheckBox();
		JLabel label = new JLabel();
		
		public CheckBoxTreeNodeRenderComponent()
		{
			setLayout(null);
			add(checkBox);
			add(label);
		}

	    @Override
	    public Dimension getPreferredSize()
	    {
	        Dimension d_check = checkBox.getPreferredSize();
	        Dimension d_label = label.getPreferredSize();	        
	        int maxHeight = Math.max(d_check.height, d_label.height);
	        return new Dimension(d_label.width + d_check.width, maxHeight);
	    }

	    @Override
	    public void validate()
	    {
	        Dimension checkBoxDimension = checkBox.getPreferredSize();
	        Dimension labelDimension = label.getPreferredSize();
	        
	        int maxHeight = Math.max(checkBoxDimension.height, labelDimension.height);
	        int y_check = (maxHeight - checkBoxDimension.height)/2;
	        int y_label = (maxHeight - labelDimension.height)/2;

	        checkBox.setLocation(0,y_check);
	        checkBox.setBounds(0,y_check,checkBoxDimension.width,checkBoxDimension.height);
	        label.setLocation(checkBoxDimension.width,y_label);   
	        label.setBounds(checkBoxDimension.width,y_label,labelDimension.width,labelDimension.height);    
	    }
	    
	    public JLabel getLabel() 
	    {
			return label;
		}
	}
	
	public class TestTreeCellRenderer extends DefaultTreeCellRenderer
	{
		CheckBoxTreeNodeRenderComponent checkBoxTreeNodeRenderComponent;
		public TestTreeCellRenderer(CheckBoxTreeNodeRenderComponent checkBoxTreeNodeRenderComponent)
		{
			this.checkBoxTreeNodeRenderComponent = checkBoxTreeNodeRenderComponent;
		}
		
	    public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded,
	                                                  boolean leaf, int row, boolean hasFocus)
	    {
	    	JLabel label = checkBoxTreeNodeRenderComponent.getLabel();
	    	label.setText(value.toString());
	        return checkBoxTreeNodeRenderComponent;
	    }
	}
	
	public class CheckBoxTreeNodeEditorComponent extends JPanel
	{
		JCheckBox checkBox = new JCheckBox();
		JTextField textField = new JTextField();
		
		public CheckBoxTreeNodeEditorComponent()
		{
//	    	FlowLayout layout = new FlowLayout(FlowLayout.LEADING, 0, 0);
//	        setLayout(layout);
	        setLayout(null);
			add(checkBox);
			add(textField);
		}

	    @Override
	    public Dimension getPreferredSize()
	    {
	        Dimension d_check = checkBox.getPreferredSize();
	        Dimension d_label = textField.getPreferredSize();	        
	        int maxHeight = Math.max(d_check.height, d_label.height);
	        return new Dimension(d_label.width + d_check.width, maxHeight);
	    }

	    @Override
	    public void validate()
	    {
	        Dimension checkBoxDimension = checkBox.getPreferredSize();
	        Dimension labelDimension = textField.getPreferredSize();
	        
	        int maxHeight = Math.max(checkBoxDimension.height, labelDimension.height);
	        int y_check = (maxHeight - checkBoxDimension.height)/2;
	        int y_label = (maxHeight - labelDimension.height)/2;

	        checkBox.setLocation(0,y_check);
	        checkBox.setBounds(0,y_check,checkBoxDimension.width,checkBoxDimension.height);
	        textField.setLocation(checkBoxDimension.width,y_label);   
	        textField.setBounds(checkBoxDimension.width,y_label,labelDimension.width,labelDimension.height);    
	    }
	    
	    public JTextField getTextField() 
	    {
			return textField;
		}
	}
	
	public class TestTreeCellEditor implements TreeCellEditor
	{
		private CheckBoxTreeNodeEditorComponent checkBoxTreeNodeEditorComponent;		
		public TestTreeCellEditor(CheckBoxTreeNodeEditorComponent checkBoxTreeNodeEditorComponent)
		{
			this.checkBoxTreeNodeEditorComponent = checkBoxTreeNodeEditorComponent;
		}
		
		@Override
		public Object getCellEditorValue()
		{
			return checkBoxTreeNodeEditorComponent.getTextField().getText();
		}
		
		@Override
		public boolean isCellEditable(EventObject anEvent) {return true;}
		@Override
		public boolean shouldSelectCell(EventObject anEvent) {return true;}
		@Override
		public boolean stopCellEditing() {return false;}
		@Override
		public void cancelCellEditing() {}
		@Override
		public void addCellEditorListener(CellEditorListener l) {}
		@Override
		public void removeCellEditorListener(CellEditorListener l) {}
		@Override
		public Component getTreeCellEditorComponent(JTree tree, Object value,
				boolean isSelected, boolean expanded, boolean leaf, int row) 
		{
			JTextField textField = checkBoxTreeNodeEditorComponent.getTextField();
			textField.setText(value.toString());
			return checkBoxTreeNodeEditorComponent;
		}		
	}
}

Obwohl der TreeCellRenderer und der TreeCellEditor identisch aufgebaut sind, zeigt der TreeCellEditor (nur unter Linux) nichts an. Wenn ich das Null-Layout in ein Flow-Layout aendere (Zeile 125-127) geht es.

Ich benutze unter Mint folgendes JDK:

java version "1.6.0_24"
OpenJDK Runtime Environment (IcedTea6 1.11.4) (6b24-1.11.4-1ubuntu0.12.04.1)
OpenJDK Client VM (build 20.0-b12, mixed mode, sharing)

Hat jemand eine Erklaerung? Was mache ich falsch?

Danke!

Gruss, FFNB.
 
Mahlzeit,

Ich loese mal auf (vielleicht interessiert es ja den ein oder anderen)...

warum auch immer - die "validate()"-Methode der Editor-Komponente wird unter Linux nicht "automatisch" aufgerufen. Somit haben die Komponenten auf dem Panel keine Groesse und Position und werden auf 'nem Null-Layout nicht dargestellt.

Unter Windows ist der CallStack fuer die "validate()"-Methode der Editor-Komponente folgender:

Code:
java.lang.Exception
	at TreeTest$CheckBoxTreeNodeEditorComponent.validate(TreeTest.java:147)
	at javax.swing.plaf.basic.BasicTreeUI.startEditing(BasicTreeUI.java:2078)
	at javax.swing.plaf.basic.BasicTreeUI$Handler.handleSelection(BasicTreeUI.java:3519)
	at javax.swing.plaf.basic.BasicTreeUI$Handler.mousePressed(BasicTreeUI.java:3459)
	at java.awt.Component.processMouseEvent(Component.java:6287)
	at javax.swing.JComponent.processMouseEvent(JComponent.java:3267)
	at java.awt.Component.processEvent(Component.java:6055)
	at java.awt.Container.processEvent(Container.java:2039)
	at java.awt.Component.dispatchEventImpl(Component.java:4653)
	at java.awt.Container.dispatchEventImpl(Container.java:2097)
	at java.awt.Component.dispatchEvent(Component.java:4481)
	at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4575)
	at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4233)
	at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4166)
	at java.awt.Container.dispatchEventImpl(Container.java:2083)
	at java.awt.Window.dispatchEventImpl(Window.java:2482)
	at java.awt.Component.dispatchEvent(Component.java:4481)
	at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:648)
	at java.awt.EventQueue.access$000(EventQueue.java:84)
	at java.awt.EventQueue$1.run(EventQueue.java:607)
	at java.awt.EventQueue$1.run(EventQueue.java:605)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87)
	at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:98)
	at java.awt.EventQueue$2.run(EventQueue.java:621)
	at java.awt.EventQueue$2.run(EventQueue.java:619)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:618)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
	at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

Keine Ahnung, wo hier plattformabhaengiges passiert.

Die Loesung ist, zwischen Zeile 194 und 195:
Java:
checkBoxTreeNodeEditorComponent.validate();
einzufuegen.

Gruss, FFNB.
 
Genau deshalb (siehe link in Signatur) ist Null layout böse. Anstatt deiner validate Methode kannst du diesen Code auf genausogut in einen eigenen Layoutmanager schreiben und dann läuft das überall.
 
Mahlzeit,

super Idee! Ich hab mir nun einen eigenen LayoutManager geschrieben, der die "layoutContainer(Container parent)" und "preferredLayoutSize(Container parent)" Methoden entsprechend meiner "getPreferredSize()" und "validate()" Methoden implementiert... funktioniert prima und war gar nicht so kompliziert.

Danke!

Gruss, FFNB.
 

Neue Themen


Zurück
Oben