Редактор JTree не устанавливает переменные

Я пытаюсь использовать 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;
    }
}

person glend    schedule 25.01.2016    source источник
comment
В вашем коде нет enum HazardSelection.   -  person aterai    schedule 25.01.2016
comment
@aterai; я включил код перечисления.   -  person glend    schedule 25.01.2016


Ответы (1)


Проблема заключается в переопределении метода 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();
}

Удачи.

person STaefi    schedule 25.01.2016
comment
Это работает! за исключением того, что он устанавливает JLabel в значение JComboBox, это не то, что я хочу, в качестве временного исправления я делаю return val;. Я чувствую, что этот оператор return вернет и JComboBox, и JLabel. Я продолжу экспериментировать, но это шаг в правильном направлении. Спасибо! - person glend; 25.01.2016
comment
Добро пожаловать! Если вы нашли этот пост полезным, можете принять его. - person STaefi; 25.01.2016
comment
Интересно, что даже несмотря на то, что я помещаю слушателя на JComboBox, его установка JLabel - вот настоящая проблема, как я могу заставить слушателя на JComboBox возвращаться на JComboBox? - person glend; 25.01.2016