所以我有一个JTree,它将有不同数量的叶子和节点,我需要在树的叶子旁边添加JComboBox,但没有树的其他部分。我尝试使用树叶的屏幕位置和边框布局来实现这一点,但是这些框总是最终关闭,当我有很多叶子时,情况会变得非常糟糕,而且它们似乎也只是定位在框架中的 1 个位置,并且随着每个新组合框的添加而不断挤压自己变薄。我怎么可能实现我想要的东西?
我需要在树叶旁边添加 JComboBoxes,但没有树的其他部分
考虑创建自己的TreeCellRenderer
,将JComboBox
直接合并到JTree
中。要允许编辑 JComboBox,您还需要实现一个处理编辑组件以及编辑完成后对该组件执行的操作的TreeCellEditor
。下面是一个非常简单的例子,在JTree
的叶子中,在JLabel
旁边放置一个JComboBox
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];
}
}