I have a custom JTree implementation that implemts convertValueToText
. This implementation depends on some global state. If the returned string is longer (actually I think wider as in pixels triggers it) than a previously returned string, the text will be truncated and padded with "...". This is true when the redrawing is caused by (de)selecting the element or a repaint
on the tree.
Is it valid to implement convertValueToText
in such a way? (I recognize that the tree display will not automatically be updated).
How can I get rid of the "..." and force all elements to be correctly drawn with their current textual value?
Update2:
Appearently I violated Swings rather strict treading policy (http://docs.oracle.com/javase/6/docs/api/javax/swing/package-summary.html). Doing the update with:
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
for (int row = 0; row < tree.getRowCount(); row++) {
((DefaultTreeModel) tree.getModel())
.nodeChanged((TreeNode) tree.getPathForRow(row)
.getLastPathComponent());
}
}
});
appears to work correctly.
Update:
Here is a minimal example:
import java.util.Enumeration;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JTree;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
public class WeirdTreeFrame extends JFrame {
public class WeirdTree extends JTree {
public WeirdTree(TreeNode root) {
super(root);
}
@Override
public String convertValueToText(Object value, boolean selected,
boolean expanded, boolean leaf, int row, boolean hasFocus) {
return super.convertValueToText(value, selected, expanded, leaf, row, hasFocus);
}
}
public class WeirdNode implements TreeNode {
protected WeirdNode parent;
protected WeirdNode children[];
protected int dephth;
protected String name;
protected String names[] = {"Foo", "Bar", "Ohh"};
public long superCrazyNumber;
public WeirdNode(WeirdNode parent, String name) {
this.parent = parent;
this.name = name;
if (parent != null) {
dephth = parent.dephth + 1;
} else {
dephth = 0;
}
if (dephth < 10) {
children = new WeirdNode[3];
for (int i = 0; i < 3; i++) {
children[i] = new WeirdNode(this, name + names[i]);
}
}
}
@Override
public TreeNode getChildAt(int childIndex) {
if (childIndex >= getChildCount()) return null;
return children[childIndex];
}
@Override
public int getChildCount() {
return (children != null) ? children.length : 0;
}
@Override
public TreeNode getParent() {
return parent;
}
@Override
public int getIndex(TreeNode node) {
for (int i = 0; i < children.length; i++) {
if (children[i] == node) return i;
}
throw new RuntimeException();
}
@Override
public boolean getAllowsChildren() {
return true;
}
@Override
public boolean isLeaf() {
return getChildCount() == 0;
}
@Override
public Enumeration children() {
return new Enumeration<TreeNode>() {
int nextIdx = 0;
@Override
public boolean hasMoreElements() {
return nextIdx < getChildCount();
}
@Override
public TreeNode nextElement() {
return getChildAt(nextIdx++);
}
};
}
@Override
public String toString() {
return "[" + dephth + "]" + name + "@" + superCrazyNumber;
}
}
public WeirdNode root;
private WeirdTree tree;
public WeirdTreeFrame() {
root = new WeirdNode(null, "Blubb");
tree = new WeirdTree(root);
add(tree);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(500,500);
setVisible(true);
}
public void update() {
for (int row = 0; row < tree.getRowCount(); row++) {
((DefaultTreeModel) tree.getModel()).nodeChanged((TreeNode)tree.getPathForRow(row).getLastPathComponent());
}
}
public static void main(String[] args) {
WeirdTreeFrame frame = new WeirdTreeFrame();
Random rnd = new Random(41);
for (long i = 0; ; i++) {
for (WeirdNode node = frame.root; node != null; node = (WeirdNode)node.getChildAt(rnd.nextInt(3))) {
node.superCrazyNumber++;
}
if (i % 1e7 == 0) {
System.out.println("Update: " + i);
frame.update();
}
}
}
}
With the update()
method I tried to fire the appropriate events to make sure all visible nodes are updated correctly. As you can see some computation is happening in parallel and perioically during the computation I want to update the tree labels (NOT the structure).
The issue with the update()
method is that some nodes are labled completely wrong as you can see in the attached picture (should be "[0]..." for root node, "[n].."for nth level)
I assume this is some race condition.