Swing JTree UI Probleme

CroniD

Aktives Mitglied
Morgen liebe Gemeinde. :)

Ich habe heute zum ersten Mal mit der JTree Komponente gearbeitet, besser gesagt mit der erweiterten JXTree aus SwingX.

Ich wollte gerne eine Art Verzeichnis anzeigen lassen, die vom Aussehen dem gleich kommt was ich aus ThunderBird3 kenne (die Konten-Darstellung auf der linken Seite).
Bildchen: http://ubuntublog.ch/wp-content/upl...osteingang-Mozilla-Thunderbird-3.0-Beta-4.png

JTree ist ansich recht intuitiv, aber folgende Dinge bekam ich bisher nicht hin:
- Bei Selektion/Fokusierung eines Nodes soll der Hintergrundbalken über die ganze verfügbare Breite gehen
- die Nodes auf Ebene 1 (root = Ebene 0) sollen keinen Abstand zum Rand haben

Ich habe erstmal angefangen mir einen TreeCellRenderer zu schreiben und habe dafür von DefaultTreeCellRenderer geerbt. Mein erster Gedanke war, da es sich im Prinzip um ein JLabel handelt einfach die PrefSize auf die Größe des verfügbaren Platzes zu setzen. Das löste scheinbar das erste Problem, aber wenn sich die verfügbare Breite ändert, dann junkt es dem Note nicht. :-/

Ist eine eingebettete Klasse. Der Tree wird übrigens in ein JScrollPane gepackt und dieses wiederum in eine JSplitPane. D.h. der verfügbare Platz, die Breite, wird von der JSplitpane bestimmt.
Java:
private class DataOverviewTreeCellRenderer extends DefaultTreeCellRenderer {
		private int width = 0;
		public DataOverviewTreeCellRenderer() {
			super();
		}

		@Override public Component getTreeCellRendererComponent(JTree tree, Object value,
				boolean selected, boolean expanded, boolean leaf, int row,
				boolean hasFocus) {
			super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
			if (splitpane.getLastDividerLocation() <= 0) {
				width = splitpane.getDividerLocation();
			} else {
				width = splitpane.getLastDividerLocation();
			}
			this.setPreferredSize(new Dimension(width, this.getPreferredSize().height));
			
			return this;
		}
	}
Das Problem mit der dynamischen Pref-Änderung liegt aber wohl am ScrollPane, oder?

Was ich von euch nun gerne wissen möchte ist
1. bin ich auf dem richtigen Weg?
2. Habt ihr Tips für meine beiden Probleme? (Quellcode müsst ihr nicht extra schreiben)

Gruß
CroniD
 
Zuletzt bearbeitet:

KrokoDiehl

Top Contributor
Ohne es probiert zu haben, aber du kannst mal probieren, die Größe des Renderers nicht über die Splitpane, sondern über den JTree zu ermitteln. In der get-Methode des Renderers kannst du über
Java:
Rectangle rect = tree.getRowBounds(row);
ermitteln, wie groß die Renderer-Komponente sein muss. Diesen verfügbaren Platz müsstest du dann entsprechend füllen, bzw. im Idealfalls als Größe für den Renderer nehmen. Vielleicht kann man damit auch das zweite Problem lösen.

Was ich hier aber nicht weiß, ist ob
Code:
getRowBounds()
tatsächlich die volle Breite des JTree zurück gibt. Falls nicht, würde ich dennoch über die Breite des JTree gehen, anstelle der SplitPane.
 

CroniD

Aktives Mitglied
Nee, bei beiden von dir vorgeschlagenen Möglichkeiten kommt eine saftige "Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError" mit einer langen, sehr langen Liste. ^^

Ist auch logisch, weil die abgefragten Eigenschaften vom Tree natürlich erst nach dem Rendern der Einträge zur Verfügung stehen. Während des Renders diese Werte abzufragen resultiert in einer Endlosschleife. Folglich StackOverflowError. :eek:
 

KrokoDiehl

Top Contributor
Das ist natürlich blöd. Spontan habe ich dazu erstmal keine Idee mehr. Von der Darstellung her ist das, was du erreichen willst, auch einer JList nicht unähnlich, aber dann das mit dem Auf- und Zuklappen der Knoten zu erreichen ist womöglich auch nicht einfacher, als den Renderer des JTrees umzugestalten.
 

CroniD

Aktives Mitglied
Na ja, eine Kombination aus JListen wäre eigentlich nicht so schwer. Klar, man müsste eigene Interfaces definieren, einen komplett eigenen Controller, ein DefaultModel und DefaultRenderer, aber mittlerweile schätze ich das als leichter ein in dem Kontext. ^^

Probleme werde ich damit nur haben was die Performance angeht, denke ich. Aber so viele Einträge sollen nicht dargestellt werden, also denke ich, dass ich das mal heute in Angriff nehmen werde. :)
 

Michael...

Top Contributor
JTree ist graphisch gesehen eine recht komplexe Komponente. Eine saubere Lösung wirst Du vermutlich nur erhalten, wenn Du dessen UI überschreibst. Hier mal ein Bsp. vielleicht kommt über den Ansatz weiter:
Java:
import java.awt.*;

import javax.swing.*;
import javax.swing.plaf.basic.BasicTreeUI;
import javax.swing.tree.TreePath;

public class TreeLineSelectionDemo extends JFrame {
	
	private int width=0;
	
	public TreeLineSelectionDemo() {
		
		JTree tree = new JTree() {
			public void paintComponent(Graphics g) {
				width = this.getWidth();
				super.paintComponent(g);
			}
		};
		BasicTreeUI ui = new BasicTreeUI() {
			protected void paintRow(Graphics g, Rectangle clipBounds, Insets insets, Rectangle bounds, TreePath path, int row, boolean isExpanded, boolean hasBeenExpanded, boolean isLeaf) {
				bounds.width = width - bounds.x;
				super.paintRow(g, clipBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf);
			}
		};
		tree.setUI(ui);
		JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, new JScrollPane(tree), new JLabel("Hallo", JLabel.CENTER));
		this.getContentPane().add(split);
	}
	
	public static void main(String[] args) {
		JFrame frame = new TreeLineSelectionDemo();
		frame.setBounds(0, 0, 500, 300);
		frame.setLocationRelativeTo(null);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}
}
 

CroniD

Aktives Mitglied
Okay, habe nun die Zeit gefunden und deinen vorgeschlagenen Ansatz weiter verfolgt und es geht. :)

Es gibt aber eine Einschränkung: Leider kann man den Rahmen der Selektion nicht vergrößern, da die zuständige Methode in der BasicTreeUI Klasse "private" ist (blöder Designfehler). Deswegen ist es per Default deaktiviert im Konstruktor.
Ach und mit Nimbus gibt es ein grafisches Problem bezüglich der Expanded und Collapsed Icons (also den "+" und "-" Buttons). Sie werden normalerweise bei einer Selektion weiß dargestellt, aber sie bleiben schwarz mit meiner Klasse, was nicht schlimm ist, weil ich kein Nimbus verwende, aber falls irgendwer diese Klasse verwenden will, dann sei es an dieser Stelle erwähnt.
Ansonsten ist die Darstellung mit den Standard LAF unter Windows kompatibel. :)

Hier der QuellCode (mit ausführbarem Beispiel):
Java:
public class JTreeNSSC extends JTree {

	private Color bColor;
	private int width = 0;

	public JTreeNSSC() {
		this(getDefaultTreeModel());
	}
	
	public JTreeNSSC(Object[] value) {
		this(createTreeModel(value));
		this.expandRoot();
	}
	
	public JTreeNSSC(Hashtable<?, ?> value) {
		this(createTreeModel(value));
		this.expandRoot();
	}

	public JTreeNSSC(TreeNode root, boolean asksAllowsChildren) {
		this(new DefaultTreeModel(root, asksAllowsChildren));
	}

	public JTreeNSSC(TreeNode root) {
		this(root, false);
	}

	public JTreeNSSC(Vector<?> value) {
		this(createTreeModel(value));
		this.expandRoot();
	}
	
	public JTreeNSSC(TreeModel dataModel) {
		super(dataModel);
		this.setRootVisible(false);
		this.setShowsRootHandles(true);
		this.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
		UIManager.put("Tree.drawDashedFocusIndicator", false);
		UIManager.put("Tree.paintLines", false);
        DefaultTreeCellRenderer dtcr = new DefaultTreeCellRenderer();
        dtcr.setBorderSelectionColor(null);
        this.bColor = dtcr.getBackgroundSelectionColor();
        if (this.bColor == null) {
        	this.bColor = UIManager.getColor("Tree.selectionBackground");
        	if (this.bColor == null) {
        		this.bColor = Color.BLUE;
        	}
        }
        this.setCellRenderer(dtcr);
        this.setUI(new MyBasicTreeUI());
	}
	
	private void expandRoot() {
		TreeModel model = getModel();
		if (model != null && model.getRoot() != null) {
			expandPath(new TreePath(model.getRoot()));
		}
	}
	
	@Override public void paintComponent(Graphics g) {
        width = this.getWidth();
        super.paintComponent(g);
    }
	
	@Override public void setUI(TreeUI ui) {
		if (ui instanceof MyBasicTreeUI) {
			super.setUI(ui);
		} else {
			super.setUI(new MyBasicTreeUI());
		}
	}

    public class MyBasicTreeUI extends BasicTreeUI {
    	
		public MyBasicTreeUI() {
			super();
		}
		
		@Override public void paint(Graphics g, JComponent c) {
			if (tree != c) {
			    throw new InternalError("incorrect component");
			}
			// Should never happen if installed for a UI
			if(treeState == null) {
			    return;
			}
			// paint the selection before any other things
			int[] rows = tree.getSelectionRows();
			if (rows != null && rows.length > 0) {
				Color old = g.getColor();
				g.setColor(bColor);
				TreePath path = null;
				Rectangle bounds = null;
				for (int row : rows) {
					path = tree.getPathForRow(row);
					if (path != null) {
						bounds = getPathBounds(tree, path);
						if (bounds != null) {
							g.fillRect(0, bounds.y, bounds.width, bounds.height);
							path = null;
							bounds = null;
						}
					}
					
				}
				g.setColor(old);
			}
			super.paint(g, c);
		}
		
		@Override public Rectangle getPathBounds(JTree tree, TreePath path) {
			Rectangle bounds = super.getPathBounds(tree, path);
			if (bounds != null) {
				// do not miss a selection click because of wrong bound values
				bounds.x = 0;
				bounds.width = width;
			}
			return bounds;
    	}
    }
	
	public static void main(String[] args) {
		try {
			UIManager.setLookAndFeel(UIManager.getInstalledLookAndFeels()[3].getClassName());
		} catch (Exception e) {}
		String title = "JTreeNSSC: "
			+System.getProperty("os.name")+" "
			+System.getProperty("java.runtime.version");
		JFrame f = new JFrame(title);
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		Container cont = f.getContentPane();
		JPanel pane = new JPanel(new BorderLayout());
		pane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
		
		JTreeNSSC jt = new JTreeNSSC();
		
		JTree t = new JTree();
		
		JPanel trees = new JPanel(new GridLayout(1, 0));
		trees.add(new JScrollPane(jt));
		trees.add(new JScrollPane(t));
		pane.add(trees, BorderLayout.CENTER);
		JPanel texts = new JPanel(new GridLayout(1, 0));
		texts.add(new JLabel("Standard JTreeNSSC", JLabel.CENTER));
		texts.add(new JLabel("Standard JTree", JLabel.CENTER));
		pane.add(texts, BorderLayout.PAGE_START);
		cont.add(pane);
		f.setSize(600, 300);
		f.setLocationRelativeTo(null);
		f.setVisible(true);
	}
}

BTW: Danke Michael... und KrokoDiehl :)
 
Zuletzt bearbeitet:
Ähnliche Java Themen
  Titel Forum Antworten Datum
H JTree Probleme AWT, Swing, JavaFX & SWT 9
D Swing Probleme mi JTree & TreeModeln usw AWT, Swing, JavaFX & SWT 5
T Probleme mit JSplitPane, JScrollPane, JTree AWT, Swing, JavaFX & SWT 3
R Probleme mit JTree / setUserObject() AWT, Swing, JavaFX & SWT 4
L Probleme mit JTree AWT, Swing, JavaFX & SWT 3
C JTree bereitet große Probleme, kann uns bitte jemand helfen! AWT, Swing, JavaFX & SWT 6
K Probleme mit der Anzeige eines einzigen Nodes in einem JTree AWT, Swing, JavaFX & SWT 9
D JTree Drag and Drop / drop - Probleme AWT, Swing, JavaFX & SWT 4
G Probleme mit JTree: "pathByAddingChild" NPExceptio AWT, Swing, JavaFX & SWT 2
K Probleme mit Listener für JTree AWT, Swing, JavaFX & SWT 4
M JTree Probleme AWT, Swing, JavaFX & SWT 6
FrittenFritze JTree, LazyLoading und "Rückwärtstraversion" AWT, Swing, JavaFX & SWT 3
J Falsches Rendern durch JCheckBox in eigenem JTree AWT, Swing, JavaFX & SWT 6
F jTree und das Model aus einer eigenen Klasse AWT, Swing, JavaFX & SWT 1
F Jtree aus Klasse mit Arraylisten AWT, Swing, JavaFX & SWT 1
A Swing JList zu JTree AWT, Swing, JavaFX & SWT 11
richis-fragen JTree +/- verschwidet wenn Knoten keine Kinder hat... AWT, Swing, JavaFX & SWT 6
RalleYTN Modaler Dialog und JTree Node mit sehr... seeeeehr vielen Elementen AWT, Swing, JavaFX & SWT 6
Z Swing JTree DefaultMultipleTreeNode Repräsentation ändern AWT, Swing, JavaFX & SWT 1
Z Swing Drag&Drop zwischen JTable und JTree AWT, Swing, JavaFX & SWT 4
W Swing Anzeigefehler bei JTree AWT, Swing, JavaFX & SWT 1
S Zwei JTree, ein Model, bei Selection im ersten JTree soll der zweite die Inhlate anzeigen AWT, Swing, JavaFX & SWT 2
S JRadioButton und JCheckBox im JTree AWT, Swing, JavaFX & SWT 14
H Swing JTree: Zählt der rootNode mit? AWT, Swing, JavaFX & SWT 2
krgewb Swing JTree - Farbe von nodes ändern AWT, Swing, JavaFX & SWT 4
R JTree behandeln AWT, Swing, JavaFX & SWT 2
E Swing Copy und Paste eines einzelnen Knoten aus einem JTree AWT, Swing, JavaFX & SWT 1
U dynamisches JTree erstellen AWT, Swing, JavaFX & SWT 2
J JTree updaten AWT, Swing, JavaFX & SWT 2
N Swing JTree Problem beim erstellen der Knoten AWT, Swing, JavaFX & SWT 0
H JTree in JScrollPane passt sich nicht an Größe von JPanel an AWT, Swing, JavaFX & SWT 2
T Swing API Frage zu Verzeichnisbäumen und JTree AWT, Swing, JavaFX & SWT 1
T JTree mit Symbolen? AWT, Swing, JavaFX & SWT 8
R Anfängerfrage: Ansichten des JTree AWT, Swing, JavaFX & SWT 1
H Swing JTree Minimumgröße AWT, Swing, JavaFX & SWT 2
F Swing JTree + DiffUtils // Markierung Nodes aufheben AWT, Swing, JavaFX & SWT 2
I JTree wird nicht angezeigt AWT, Swing, JavaFX & SWT 3
M Swing JTree AWT, Swing, JavaFX & SWT 4
M Nodes in JTree nicht anzeigen AWT, Swing, JavaFX & SWT 0
T JTree mit Cloud verbinden AWT, Swing, JavaFX & SWT 0
F Swing Drag and Drop in JTree aus verschiedenen Listen AWT, Swing, JavaFX & SWT 6
M JButton wird von JTree überdeckt AWT, Swing, JavaFX & SWT 4
J Auf Dateien in JTree zugreifen AWT, Swing, JavaFX & SWT 15
F jTree.startEditingAtPath(path); funktioniert nicht bei eigenem CellEditor? AWT, Swing, JavaFX & SWT 8
D Swing JTree Steuerung AWT, Swing, JavaFX & SWT 11
S Swing JTree verwirrt mich AWT, Swing, JavaFX & SWT 2
T JTree - Elemente mit Doppelklick auswählen AWT, Swing, JavaFX & SWT 6
J JTree speichern AWT, Swing, JavaFX & SWT 4
N Swing JTree TreeCellRenderer mit html und automatischen Zeilenumbruch AWT, Swing, JavaFX & SWT 8
O Swing JTree um Label (oder Panel) erweitern AWT, Swing, JavaFX & SWT 9
T JTree, Knoten mehrmals verwenden AWT, Swing, JavaFX & SWT 5
B JTree mit Ordneransicht in JPanel einbinden AWT, Swing, JavaFX & SWT 4
D JTree node reagiert bei Klick nicht immer AWT, Swing, JavaFX & SWT 2
M Swing JTree: Wie kann ich die Hintergrundfarbe der selection ändern?!?! AWT, Swing, JavaFX & SWT 7
D Mehrmals auf Node im JTree klicken AWT, Swing, JavaFX & SWT 2
D JSplitPane, Jtree, CardLayout (constraint must be a string) AWT, Swing, JavaFX & SWT 9
N Swing FileFilter lässt JTree sich nicht öffnen AWT, Swing, JavaFX & SWT 2
X Swing 2 TreeModel und ein JTree synchronisieren AWT, Swing, JavaFX & SWT 3
N Swing JTree TreePath zu Windows Pfad? AWT, Swing, JavaFX & SWT 2
RELAXccc Swing JTree + JScrollPane, refresh Problem AWT, Swing, JavaFX & SWT 17
X Swing JTree aktualisieren AWT, Swing, JavaFX & SWT 2
V Swing JTree - Umbenennen selbst handlen. AWT, Swing, JavaFX & SWT 2
E Übergebenem JTree Blätter hinzufügen AWT, Swing, JavaFX & SWT 2
E Wert eines selektierten Knotens in einem JTree auslesen AWT, Swing, JavaFX & SWT 3
A Swing JTree - Nodes expanden AWT, Swing, JavaFX & SWT 2
D JTree nach Klick auf einen Hyperlink aktualisieren AWT, Swing, JavaFX & SWT 3
B JTree AWT, Swing, JavaFX & SWT 9
T Menüacceleratoren verschwinden bei JTree AWT, Swing, JavaFX & SWT 5
1 Swing JTree collapse child nodes AWT, Swing, JavaFX & SWT 4
B JTree - sehr individuell AWT, Swing, JavaFX & SWT 3
G Swing JTree - Verbindungslinien entfernen AWT, Swing, JavaFX & SWT 4
A Swing Herausfinden ob bei JTree Klick auf "+"/"-" anahnd x,y AWT, Swing, JavaFX & SWT 2
S Swing JTree und seine Listener... AWT, Swing, JavaFX & SWT 4
L Swing JTree wird nicht selektiert AWT, Swing, JavaFX & SWT 2
P [JTree] Markierhilfe der Drop-Location selber gestalten. AWT, Swing, JavaFX & SWT 4
A JTree aus Pfaden erzeugen AWT, Swing, JavaFX & SWT 3
K Swing Hilfe beim JTree! AWT, Swing, JavaFX & SWT 3
X Datensätze in JTree AWT, Swing, JavaFX & SWT 2
L Update JTree Verzeichnisse AWT, Swing, JavaFX & SWT 9
E JTree Auswahl AWT, Swing, JavaFX & SWT 2
K JTree width der Treenodes auf 100% AWT, Swing, JavaFX & SWT 6
C JTree LastSelectedPathComponent benutzen? AWT, Swing, JavaFX & SWT 3
S Swing JTree Node Text nicht richtig angezeigt AWT, Swing, JavaFX & SWT 2
Landei Swing JTree mit "Tabellenzeilen"? AWT, Swing, JavaFX & SWT 5
Rudolf Swing JTree Node anhand vom Namen finden AWT, Swing, JavaFX & SWT 4
S JTree Elemente nach BaumLevel abspeichern AWT, Swing, JavaFX & SWT 2
Z JTree rootChilds AWT, Swing, JavaFX & SWT 2
D JTree DefaultMutableTreeNode ActionPerformed AWT, Swing, JavaFX & SWT 3
T JTree Daten in DB schreiben am besten SQL AWT, Swing, JavaFX & SWT 21
O JTree/TreeModel/DefaultMutableTreeNodes thread safe machen AWT, Swing, JavaFX & SWT 3
J Lazy Loading eine JTree während Scrollen AWT, Swing, JavaFX & SWT 11
S JTree & JComboBox - Elemente übers Fenster hinaus anzeigen AWT, Swing, JavaFX & SWT 9
E Swing JTree AWT, Swing, JavaFX & SWT 2
J Swing Lazy Loading in JTree wenn gescrollt wird AWT, Swing, JavaFX & SWT 3
N Knotenanordnung in JTree AWT, Swing, JavaFX & SWT 4
S JTree mit Liste zur Speicherung AWT, Swing, JavaFX & SWT 3
S Jtree CheckNode mit JPanel AWT, Swing, JavaFX & SWT 32
G JTree entfernt Nodes nicht AWT, Swing, JavaFX & SWT 12
C Swing JTree und TreeModel AWT, Swing, JavaFX & SWT 15
S Swing JTree wird nicht angezeigt AWT, Swing, JavaFX & SWT 3

Ähnliche Java Themen

Neue Themen


Oben