繁体   English   中英

什么导致任意JTree节点错误地显示他们的名字,我怎么能阻止它发生?

[英]What is causing arbitrary JTree Nodes to incorrectly display their names and how can I stop it from happening?

我已经从XML数据构建了一个相当大的JTree,实际上有数千个节点,其中大部分节点都正确显示。 但是由于某种原因,一些节点的userData字符串都没有得到充分展示,而大公被减少或完全切断...附加到名称的末尾。

在此输入图像描述

受影响的节点似乎是随机的,每次从XML刷新或重新创建树时,它们都是不同的。

我已经排除的事情:

没有足够的空间来显示全名。

  1. JTree位于具有大量水平空间的JScrollPane中,JScrollPane甚至没有显示水平滚动条来指示空间不足。

  2. 即使是最短的名字也会受到影响。

  3. 所有缩短的节点名称的截止点不一致。

从XML加载的名称不完整

  1. 如果受影响的节点不是叶子,然后展开或折叠,则在重新呈现时会正确显示全名,在此过程中根本不会查询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实际上只是扩展为包含String controlName = "CustomNodeName"javax.swing.tree.DefaultMutableTreeNode

自定义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)));
        }
}

这是一个简单的答案; 这段代码:

// 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()以这样的方式包装,以保证返回一个图标并封装缓存优化。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM