我正在尝试在Renderer
中使用JTree
作为我正在开发的Swing应用程序,仅当树是叶对象并且由流布局组成时才使用自定义渲染器。带有图像的空标签,JComboBox
,最后是包含字符串的标签。
最初Renderer
通过getTreeCellRendererComponent()
中的HazardRenderer.java
方法传递一个字符串值,然后使用编辑器setText()
中的HazardComboBox.java
方法设置它获取选定的渲染器实例并使用相同的setText()
方法设置文本。
但是,在ItemListener
内调用HazardEditor()
时,标签文字会被清除。我可以验证这一点,因为注释掉侦听器会消除问题,但我需要一个侦听器能够告诉应用程序编辑编辑器已经可靠地完成。这个问题的解决方案是什么?代码如下;
Main.java
public class Main {
public JComponent makeUI() {
JTree tree = new JTree();
tree.setEditable(true);
tree.setRootVisible(false);
tree.setCellRenderer(new HazardRenderer());
tree.setCellEditor(new HazardEditor());
//tree.setModel() excluded for brevity
return new JScrollPane(tree);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new Main().makeUI());
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
}
HazardComboBox.java
public class HazardComboBox extends JPanel {
private JLabel lblLabel = new JLabel("Placeholder");
private JComboBox comboBox = new JComboBox(HazardSelection.values());
public HazardComboBox() {
setBackground(Color.WHITE);
setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
JLabel label = new JLabel("");
label.setIcon(new ImageIcon(HazardComboBox.class.getResource("/javax/swing/plaf/metal/icons/ocean/file.gif")));
add(label);
comboBox.setBorder(new EmptyBorder(2, 5, 2, 5));
comboBox.setBackground(Color.WHITE);
add(comboBox);
lblLabel.setFont(new Font("Tahoma", Font.PLAIN, 11));
add(lblLabel);
}
public JComboBox getComboBox() {
return comboBox;
}
public JLabel getLabel() {
return lblLabel;
}
public void setText(String name) {
getLabel().setText(name);
}
}
HazardRenderer.java
public class HazardRenderer implements TreeCellRenderer {
private HazardComboBox leafRenderer = new HazardComboBox();
private DefaultTreeCellRenderer nonLeafRenderer = new DefaultTreeCellRenderer();
@Override
public Component getTreeCellRendererComponent(JTree tree, Object hazard, boolean selected, boolean expanded, boolean leaf,
int row, boolean hasFocus) {
if (leaf) {
leafRenderer.setText(hazard.toString());
return leafRenderer;
}
return nonLeafRenderer.getTreeCellRendererComponent(tree, hazard, selected, expanded, leaf, row, hasFocus);
}
}
HazardEditor.java
public class HazardEditor extends AbstractCellEditor implements TreeCellEditor {
private HazardRenderer renderer = new HazardRenderer();
private HazardComboBox component;
private DefaultMutableTreeNode treeNode;
//private ServerInfo info;
//private JComboBox comboBox;
private String val;
@Override
public Component getTreeCellEditorComponent(JTree tree, Object value,
boolean isSelected, boolean expanded, boolean leaf, int row) {
val = value.toString();
component = (HazardComboBox)renderer.getTreeCellRendererComponent(tree, value, isSelected, expanded, leaf, row, true);
if(leaf) {
treeNode = (DefaultMutableTreeNode)value;
component.setText(val);
//info = (ServerInfo)treeNode.getUserObject();
//comboBox = component.getComboBox();
ItemListener itemListener = new ItemListener() {
public void itemStateChanged(ItemEvent arg0) {
component.getComboBox().removeItemListener(this);
fireEditingStopped();
}
};
component.getComboBox().addItemListener(itemListener);
}
return component;
}
@Override
public Object getCellEditorValue() {
//info.setChecked(comboBox.isSelected());
//return info;
return null;
}
@Override
public boolean isCellEditable(EventObject event) {
if(!(event instanceof MouseEvent)) return false;
MouseEvent mouseEvent = (MouseEvent)event;
JTree tree = (JTree)event.getSource();
TreePath path = tree.getPathForLocation(mouseEvent.getX(), mouseEvent.getY());
if(path == null) return false;
Object lastComponent = path.getLastPathComponent();
if(lastComponent == null) return false;
DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode)lastComponent;
return treeNode.isLeaf();
}
}
HazardSelection.java
public enum HazardSelection {
NOTCONSIDERED("Not Considered"), NOTAPPLICABLE("Not Applicable"), CONSIDERED("Considered"), HAZARD("Hazard");
private String name;
private HazardSelection (String n) {
name = n;
}
@Override
public String toString() {
return name;
}
}
答案 0 :(得分:3)
问题在于覆盖getCellEditorValue()
中的HazardEditor.java
方法。你这样做了如下:
@Override
public Object getCellEditorValue() {
//info.setChecked(comboBox.isSelected());
//return info;
return null;
}
因此,您要返回null
,然后您的Renderer
会将null呈现为标签的文字。
您可以按照以下方式更正:
@Override
public Object getCellEditorValue() {
return component.getComboBox().getSelectedItem();
}
祝你好运。