Hi all out there
I want to come back to this dammed old JTree problem which doesn't seem
to be solved correctly. Look at the code at the end, run it an press
the switch button. What you see is that the long text gets abbreviated
with an ellipse (...). The usual solutions hack around by setting the
initial text to the longest one which will ever be displayed. That's
not the kind of solution I try to find. The usual advises are to use
validate(), which - together with invalidate and revalidate - do not
solve the problem.
I've read in one post that the bounds of the nodes are cached and
recalculated only upon value changes of the node. Is there a proper way
to solve this issue? How can this cache be invalidated. Any hints on
the insight of this would be highly appreciated.
Thanks in advance.
Daniel Frey
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.tree.*;
public class Test {
static final String TEXT_1 = " - short";
static final String TEXT_2 = " - a really long text";
static String switchText = TEXT_1;
public static void main(String args[]) {
final JTree t = new JTree();
t.setCellRenderer(new DefaultTreeCellRenderer() {
public Component getTreeCellRendererComponent(
JTree t, Object o, boolean s, boolean e,
boolean l, int r, boolean f) {
final JLabel label = (JLabel)
super.getTreeCellRendererComponent(
t, o, s, e, l, r, f);
label.setText(label.getText() + switchText);
return label;
}
});
final JButton b = new JButton("switch");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
switchText = (switchText == TEXT_1 ? TEXT_2 : TEXT_1);
t.invalidate();
t.validate();
t.revalidate();
t.repaint();
}
});
final JFrame f = new JFrame();
f.getContentPane().add(b, BorderLayout.NORTH);
f.getContentPane().add(new JScrollPane(t),
BorderLayout.CENTER);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(200, 200);
f.setVisible(true);
}
}
Roland - 01 Sep 2005 22:48 GMT
> Hi all out there
>
[quoted text clipped - 41 lines]
> public void actionPerformed(ActionEvent e) {
> switchText = (switchText == TEXT_1 ? TEXT_2 : TEXT_1);
TreeModel tm = t.getModel();
if (tm instanceof DefaultTreeModel) {
DefaultTreeModel dtm = (DefaultTreeModel) tm;
signalNodeChanged(dtm, (TreeNode) dtm.getRoot());
} else {
System.err.println("Unsupported tree model:"
+ " not an instance of "
+ DefaultTreeModel.class);
}
}
private void signalNodeChanged(
DefaultTreeModel dtm, TreeNode node) {
if (dtm != null && node != null) {
dtm.nodeChanged(node);
for (Enumeration i = node.children();
i.hasMoreElements();) {
signalNodeChanged(dtm, (TreeNode) i.nextElement());
}
}
}
> });
> final JFrame f = new JFrame();
[quoted text clipped - 6 lines]
> }
> }
You somehow have to signal that the text of each node has changed, i.e.
fire a "Tree Node Changed"-event.
If your tree uses the DefaultTreeModel (which is the case in your
example above), you can call its nodeChanged() method on each node.
Using the recursive signalNodeChanged() method above, this isn't too
difficult. [Note, that the signalNodeChanged() method is also a member
of the anonymous ActionListener class, i.e. at the same level as its
actionPerformed method. For this simple example, it seems to be the most
logical place. However, you could easily move it to the enclosing class
(Test in this case) or to a separate utility class.]

Signature
Regards,
Roland de Ruiter
` ___ ___
`/__/ w_/ /__/
/ \ /_/ / \
Daniel Frey - 02 Sep 2005 10:34 GMT