【问题标题】:JTree as JComboBox Element won't show JTreeJTree 作为 JComboBox 元素不会显示 JTree
【发布时间】:2020-05-16 01:25:04
【问题描述】:

我试图将一些 JTrees 放入一个 JCombobox,以下不起作用:

import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;

public class TestDialog extends JDialog {
public TestDialog(){
    super();
    JComboBox<JTree> cb = new JComboBox<>();

    DefaultMutableTreeNode firstRoot = new DefaultMutableTreeNode("First Root Node");
    DefaultMutableTreeNode firstChild = new DefaultMutableTreeNode("First Child Node");
    DefaultMutableTreeNode secondChild = new DefaultMutableTreeNode("Second Child Node");
    firstRoot.add(firstChild);
    firstRoot.add(secondChild);

    JTree firstTree = new JTree(firstRoot);
    cb.addItem(firstTree);

    DefaultMutableTreeNode secondRoot = new DefaultMutableTreeNode("Second Root Node");
    DefaultMutableTreeNode childOfSecondNode = new DefaultMutableTreeNode("Child of Second Node");
    secondRoot.add(childOfSecondNode);

    JTree secondTree = new JTree(secondRoot);
    cb.addItem(secondTree);

    add(cb);

    pack();
    setVisible(true);
}
}

对话框不会将实际的 JTree 显示为 JCombobox 的可选元素,而是显示两个长字符串,例如 javax.swing.JTree[,0,0,0x0,invalid,...]。 我的问题是,我该如何解决这个问题?

【问题讨论】:

  • "..试图将多个 JTree 放入一个 JCombobox" ... 为什么?跨度>
  • 我想对元素进行分组。一个示例是选择不同汽车的组合框,JTree 的根节点将是汽车制造商,子节点将是不同的汽车类型。这样,汽车制造商就会对汽车进行“分类”,以便更好地使用。
  • 使用多个组合框。当用户首先选择制造商时,在第二个中填充他们制造的汽车型号。要么,要么只使用标准的JTree sans 组合框。试图将一棵树塞进组合框中,我看不出有什么好处,也看不出有什么坏处。
  • 是否可以嵌套Comboboxes,因为制造商的列表会很大,而且制造商不应该是UI的主要部分。
  • 我重读了你之前的评论,现在明白你的意思了,谢谢你的回答。

标签: java swing jcombobox jtree


【解决方案1】:

您可以添加DefaultMutableTreeNode 并使用TreeCellRenderer 来绘制JComboBox 的单元格,而不是将JTree 添加到JComboBox

import java.awt.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreeModel;

public final class MainPanel {
  private Component makeUI() {
    DefaultMutableTreeNode firstRoot = new DefaultMutableTreeNode("First Root Node");
    DefaultMutableTreeNode firstChild = new DefaultMutableTreeNode("First Child Node");
    DefaultMutableTreeNode secondChild = new DefaultMutableTreeNode("Second Child Node");
    firstRoot.add(firstChild);
    firstRoot.add(secondChild);

    DefaultMutableTreeNode secondRoot = new DefaultMutableTreeNode("Second Root Node");
    DefaultMutableTreeNode childOfSecondNode = new DefaultMutableTreeNode("Child of Second Node");
    secondRoot.add(childOfSecondNode);

    DefaultMutableTreeNode hiddenRoot = new DefaultMutableTreeNode("Root");
    hiddenRoot.add(firstRoot);
    hiddenRoot.add(secondRoot);

    JPanel p = new JPanel(new BorderLayout());
    p.add(new TreeComboBox(new DefaultTreeModel(hiddenRoot)), BorderLayout.NORTH);
    p.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
    return p;
  }

  public static void main(String[] args) {
    EventQueue.invokeLater(() -> {
      JFrame f = new JFrame();
      f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
      f.getContentPane().add(new MainPanel().makeUI());
      f.setSize(320, 240);
      f.setLocationRelativeTo(null);
      f.setVisible(true);
    });
  }
}

class TreeComboBox extends JComboBox<DefaultMutableTreeNode> {
  public TreeComboBox(TreeModel model) {
    super();
    DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();
    DefaultComboBoxModel<DefaultMutableTreeNode> m = new DefaultComboBoxModel<>();
    Collections.list((Enumeration<?>) root.preorderEnumeration()).stream()
        .filter(DefaultMutableTreeNode.class::isInstance)
        .map(DefaultMutableTreeNode.class::cast)
        .filter(n -> !n.isRoot())
        .forEach(m::addElement);
    setModel(m);
  }

  @Override
  public void updateUI() {
    super.updateUI();
    JTree dummyTree = new JTree();
    TreeCellRenderer renderer = dummyTree.getCellRenderer();
    ListCellRenderer<? super DefaultMutableTreeNode> r = getRenderer();
    setRenderer((list, value, index, isSelected, cellHasFocus) -> {
      Component c = r.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
      if (value == null) {
        return c;
      }
      if (index < 0) {
        String txt = Arrays.stream(value.getPath())
            .filter(DefaultMutableTreeNode.class::isInstance)
            .map(DefaultMutableTreeNode.class::cast)
            .filter(n -> !n.isRoot())
            .map(Objects::toString)
            .collect(Collectors.joining(" / "));
        ((JLabel) c).setText(txt);
        return c;
      } else {
        boolean leaf = value.isLeaf();
        JLabel l = (JLabel) renderer.getTreeCellRendererComponent(
            dummyTree, value, isSelected, true, leaf, index, false);
        int indent = Math.max(0, value.getLevel() - 1) * 16;
        l.setBorder(BorderFactory.createEmptyBorder(1, indent + 1, 1, 1));
        return l;
      }
    });
  }
}

【讨论】:

    【解决方案2】:

    JCombobox 只能代表StringsObjects 无法表示。

    【讨论】:

    • "Objects 无法表示。" a) String Object。 b) 他们当然可以。使用适当的renderer,我们可以将FileFontBufferedImage 或 POJO 放入组合框中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-08
    • 2023-03-12
    相关资源
    最近更新 更多