java - Jtree 和组合框布局

标签 java swing user-interface layout jtree

所以我有一个 JTree,它将有不同数量的叶子和节点,我需要在树的叶子旁边添加 JComboBox,但没有树的其他部分。我尝试使用叶子的屏幕位置和边框布局来实现这一点,但盒子总是会关闭,当我有很多叶子时,情况会变得非常糟糕,而且它们似乎也只定位在框架中的 1 个位置,并且随着添加的每个新组合框不断将自己挤压得更薄。我怎样才能实现我想要的目标?

最佳答案

i need to add JComboBoxes next to the leaves of the tree but no other part of the tree

考虑创建您自己的 TreeCellRenderer,将 JComboBox 直接合并到 JTree 中。为了允许编辑 JComboBox,您还需要实现一个 TreeCellEditor 来处理编辑组件以及编辑完成时该组件发生的操作。下面是一个非常简单的示例,它将 JComboBox 放置在 JTree

叶子中的 JLabel 旁边
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");
DefaultTreeModel model = new DefaultTreeModel(root);
final JTree tree = new JTree(model);

//flyweight pattern components
//editor
final JComboBox editorComboBox = new JComboBox();
final JComboBox viewComboBox = new JComboBox();
final Box box = Box.createHorizontalBox();
final JLabel myLabel = new JLabel();
myLabel.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 10));
box.add(myLabel);
box.add(Box.createHorizontalGlue());
box.add(viewComboBox);
//Custom Renderer
DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer (){
    @Override
    public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
        super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
        if ( leaf ){
            if ( value instanceof MyLeafNode ){
                MyLeafNode node = (MyLeafNode)value;
                viewComboBox.removeAllItems();
                myLabel.setText(value.toString());
                for ( String item : node.items ){
                    viewComboBox.addItem(item);
                }
                viewComboBox.setSelectedItem(node.selected);
                return box;
            }
        }
        return this;
    }
};

//Custom Editor
final DefaultTreeCellEditor editor = new DefaultTreeCellEditor(tree, renderer){

    final ActionListener actionListener = new ActionListener(){
        @Override
        public void actionPerformed(ActionEvent e) {
            cancelCellEditing();
            tree.repaint();
        }
    };

    @Override
    public boolean isCellEditable(EventObject e){
        if ( e.getSource() instanceof JTree ){
            JTree tree = (JTree)e.getSource();
            if ( tree.getLastSelectedPathComponent() == null ){
                return false;
            }
            DefaultMutableTreeNode o = (DefaultMutableTreeNode)tree.getLastSelectedPathComponent();
            return o.isLeaf();
        }
        return false;
    }

    @Override
    public void cancelCellEditing(){
        super.cancelCellEditing();
        DefaultMutableTreeNode node = (DefaultMutableTreeNode)tree.getLastSelectedPathComponent();
        if ( node instanceof MyLeafNode) {
            String sel = editorComboBox.getSelectedItem().toString();
            MyLeafNode mln = (MyLeafNode)node;
            mln.selected = sel;
            editorComboBox.removeActionListener(actionListener);
            tree.repaint();
        }
    }

    @Override
    public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row) {
        if ( leaf ){
            if ( tree.getLastSelectedPathComponent() instanceof MyLeafNode ){
                MyLeafNode o = (MyLeafNode)tree.getLastSelectedPathComponent();
                editorComboBox.removeAllItems();
                for ( String item : o.items ){
                    editorComboBox.addItem(item);
                }
                editorComboBox.setSelectedItem(o.selected);
                editorComboBox.addActionListener(actionListener);
            }
            return editorComboBox;

        }
        return super.getTreeCellEditorComponent(tree, value, isSelected, expanded, leaf, row);
    }

};
tree.setCellRenderer(renderer);
TreePath path = new TreePath(new TreeNode[]{root});
tree.expandPath(path);

for ( int i = 0; i < 2; i++ ){
    DefaultMutableTreeNode p = new DefaultMutableTreeNode("P" + i);
    model.insertNodeInto(p, root, i);
    for ( int j = 0; j < 2; j++ ){
        String[] items = {"Item 1", "Item 2", "Item 3", "Item 4"};
        MyLeafNode n = new MyLeafNode("N" + j, items);
        model.insertNodeInto(n, p, j);
    }
    path = new TreePath(new TreeNode[]{root, p});
    tree.expandPath(path);
}
tree.setCellEditor(editor);
tree.setEditable(true);

JScrollPane scroller = new JScrollPane(tree);
frame.add(scroller);
frame.pack();
frame.setVisible(true);

其中MyLeafNode是用于存储JComboBox特定数据的自定义类:

public class MyLeafNode extends DefaultMutableTreeNode{

    private String[] items;
    private String selected;

    public MyLeafNode(String name, String...items){
        super(name);
        this.items = items;
        this.selected = items[0];
    }

}

关于java - Jtree 和组合框布局,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38724298/

相关文章:

java - spring 和 junit bean 注入(inject)和实例化

java - addActionListener 不起作用我在 .Handler 上遇到错误

java - Swing 将 JOptionPane 链接到 JFileChooser

java - 实现场景等规则的理想数据结构是什么?

java - Date() 显示有关参数不匹配的错误

从不正确的线程访问 Java android Realm

java - 如何设置Defaulttablemodel JTable中数据的对齐方式?

swing - 使用Swing进行异步UI更新

Java GUI,无需任何其他进程

asp.net - 从非常大的列表中选择一个项目