我已经从XML数据中构建了一个相当大的JTree,实际上有数千个节点,其中大多数都正确显示。但是由于某些原因,某些节点的userData
字符串没有完全显示,而是在名称末尾附加...
的情况下缩短或完全切断。
受影响的节点似乎是随机的,每次从XML刷新或重新创建树时都会有所不同。
没有足够的空间来显示全名。
JTree位于一个有足够水平空间的JScrollPane里面,JScrollPane甚至没有显示水平滚动条来表示空间不足。
即使是最短的名字也会受到影响。
所有缩短的节点名称的截止点并不一致。
从XML加载的名称不完整
根据要求对JTree背后的代码进行了一些解释:
TreeModel的创建和树的种群:
public XMLDialogTree(Document doc)
{
DefaultTreeModel treeModel = new DefaultTreeModel(buildTreeNode(doc.getElementsByTagName("Dialogs").item(0)));
setModel(treeModel);
}
// A recursive function to build the tree
private DefaultMutableTreeNode buildTreeNode(Node xmlNode)
{
// Make sure the node's name is a description of what it is, as opposed to a generic XML tag
XMLDialogTreeNode = new XMLDialogTreeNode(xmlNode.getAttributes().getNamedItem("name").getNodeValue());
treeNode.controlName = xmlNode.getNodeName();
// Add children to the treeNode based on the xmlNode's children
NodeList nodeList = xmlNode.getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++)
{
Node tempNode = nodeList.item(i);
if (tempNode.getNodeType() == Node.ELEMENT_NODE)
{
// loop again if has child nodes
treeNode.add(buildTreeNode(tempNode));
}
}
return treeNode;
}
其中doc
是包含已解析XML的org.w3c.dom.Document
,而XMLDialogTreeNode
实际上只是javax.swing.tree.DefaultMutableTreeNode
扩展为包含String controlName = "CustomNodeName"
自定义CellRenderer如下所示,代码几乎与加载自定义图标有关,不会影响显示的名称。
public class XMLDialogTreeCellRenderer extends DefaultTreeCellRenderer
{
private static final long serialVersionUID = 1L;
// Icons used in the JTree, loaded once on an as needed basis once, and stored here.
private static final Map<String, Icon> icons = new HashMap<String, Icon>();
static
{
// Make sure the default icon is loaded
loadIcon("_not_found");
}
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean exp, boolean leaf, int row, boolean hasFocus)
{
XMLDialogTreeNode node = (XMLDialogTreeNode) value;
setIcons(node.controlName);
super.getTreeCellRendererComponent(tree, value, sel, exp, false/* leaf */, row, hasFocus);
return this;
}
/**
* Assigns both the open and close icons, which are specific to a certain control. Loads them if necessary.
*
* @param controlName
* - The name of the control in the XML and the name of the image in the resources.treeIcons package.
*/
private final void setIcons(String controlName)
{
// Make sure the Node has a controlName set
if (controlName != null)
{
// Try and get a pre-loaded icon
Icon controlIcon = icons.get(controlName);
// It wasn't there, try loading it
if (controlIcon == null)
loadIcon(controlName);
// If the icon doesn't exist, it is set to a default so this code is safe
setOpenIcon(controlIcon);
setClosedIcon(controlIcon);
// Stop here so we don't just set the default icons again
return;
}
setOpenIcon(getDefaultOpenIcon());
setClosedIcon(getDefaultClosedIcon());
}
/**
*
*
* @param iconName
* @return
*/
private static final void loadIcon(String iconName)
{
URL url = XMLDialogTreeCellRenderer.class.getResource("/com/phabrix/resources/dialogTreeIcons/" + iconName + ".png");
if (url == null)
{
// Tell the developer that they need to make a new icon for a new control type
if (Main.DEBUG && !iconName.equals("Dialogs"))
System.out.println("There is no icon for the control named: " + iconName);
url = XMLDialogTreeCellRenderer.class.getResource("/com/phabrix/resources/dialogTreeIcons/_not_found.png");
}
icons.put(iconName, new ImageIcon(Toolkit.getDefaultToolkit().getImage(url)));
}
}
答案 0 :(得分:1)
这是一个简单的答案;这段代码:
// Try and get a pre-loaded icon
Icon controlIcon = icons.get(controlName);
// It wasn't there, try loading it
if (controlIcon == null)
loadIcon(controlName);
成了这段代码:
// Try and get a pre-loaded icon
Icon controlIcon = icons.get(controlName);
// It wasn't there, try loading it
if (controlIcon == null)
{
loadIcon(controlName);
controlIcon = icons.get(controlName);
}
请注意,在检查我们的Icon变量是否为null,然后确保已将Icon加载到程序中时,我现在实际上确保更新了Icon变量,使其不再为null。
我树中受影响的节点并非随机或波动,正如我之前所想。它始终是每个图标绘制的第一个节点(根据我打开树的顺序而不同)。我正在加载每个图标一次,然后缓存它(树很大并且多次重新加载相同的图标是一个很大的性能影响)。本质上,节点是用文本创建的,然后在显示后设置了一个图标,这会分散文本并导致结束被切断。如上所述,解决方案是在第一次加载图标后不要忘记设置图标。一个更好的解决方案是将icons.get()
包裹起来,以保证返回一个图标并封装缓存优化。