在单击节点时,在另一个组件的focusLost之前调用JTree valueChanged事件

时间:2013-05-20 03:16:18

标签: java swing focus jtextfield jtree

我有一个JTree,其中树的每个节点代表一些用户数据。数据是可编辑的,存储在文件/数据库中。有一堆JTextField允许您编辑/更新节点的用户数据。当JTextField失去焦点时,将触发保存数据事件。除了更改JTree中节点的选择外,这种方法很好。因为JTree事件的valueChanged发生在JTextField的focusLost之前。

以下是SSCCE:http://pastebin.com/wH1Veqdc

public class JTreeFocusTest extends JFrame{
        private static final long serialVersionUID = 1L;
        public JTreeFocusTest() {
                super("JTree Focus Test");
                JPanel panel = new JPanel(true);
                panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
                MyTree tree = new MyTree();
                panel.add(tree);
                panel.add(Box.createVerticalStrut(20));
                panel.add(new MyTextField(tree));
                panel.add(Box.createVerticalStrut(20));
                panel.add(new JTextField(30));
                getContentPane().add(panel);
                setVisible(true);
                setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                pack();
        }

        public static void main(String[] args){
                new JTreeFocusTest();
        }
}

class MyTree extends JTree{
        private static final long serialVersionUID = 1L;
        public MyTree() {
                DefaultMutableTreeNode root = new DefaultMutableTreeNode(new MyNode("Root", "Root"));
                DefaultMutableTreeNode child1 = new DefaultMutableTreeNode(new MyNode("Child 1", "DOC122122"));
                root.add(child1);
                DefaultMutableTreeNode child2 = new DefaultMutableTreeNode(new MyNode("Child 2", "DOC134342"));
                root.add(child2);
                DefaultTreeModel model = new DefaultTreeModel(root, true);
                setModel(model);
                getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
                setSelectionPath(getPathForRow(0));
        }
}

class MyTextField extends JTextField implements FocusListener, TreeSelectionListener{
        private static final long serialVersionUID = 1L;
        private MyTree tree;
        public MyTextField(MyTree tree) {
                this.tree = tree;
                setText("Some");
                addFocusListener(this);
                this.tree.addTreeSelectionListener(this);
                Dimension dim = new Dimension(200, 20);
                setPreferredSize(dim);
                setMaximumSize(dim);
                setMinimumSize(dim);
        }
        @Override
        public void focusGained(FocusEvent e) {System.out.println("TextField gained focus");}
        @Override
        public void focusLost(FocusEvent e) {
                getSelectedNodeUserObj().setValue(getText());
        }
        @Override
        public void valueChanged(TreeSelectionEvent e) {
                setText(getSelectedNodeUserObj().getValue());
        }
        private MyNode getSelectedNodeUserObj(){
                return ((MyNode)((DefaultMutableTreeNode)this.tree.getSelectionPath().getLastPathComponent()).getUserObject());
        }
}

class MyNode{
        private String label = "";
        private String value = "";

        public MyNode(String label, String value) {
                this.label = label;
                this.value = value;
        }
        public void setValue(String value){
                this.value = value;
        }
        public String getValue(){
                return value;
        }
        public String toString(){
                return label;
        }      
}

在这个例子中,我只有一个字段,但在实际应用程序中,我有几个表示用户数据的字段。另外JTextField只是一个例子,输入字段可以是JComboBox或JSpinner。

如何保存此用户数据?我很感激任何帮助/指针。

谢谢!

1 个答案:

答案 0 :(得分:2)

  

因为JTree事件的valueChanged发生在focusLost之前   JTextField中。

  • 这是逻辑排序,不要改变它,一个JComponents focusGained,然后在焦点所有者focusLost之后的焦点在窗口中

  • Focus完全异常,因为JTextComponent可以通过添加Listeners/InputMask/Formatter触发延迟事件,可以通过延迟invokeLater来解决,忘了这一点,不是你的问题

  • (我......)从TreeSelectionListener移除JTextField,移至(逻辑)JTree

  • 添加System.out.println(getText());,作为public void valueChanged(TreeSelectionEvent e) {的第一个代码行,看看发生了什么:-),有存放的地方(使用Runnable#ThreadSwingWorker来将任何内容重定向到Workers Thread

  • 然后问题是如果在JTextField中更改值并且用户单击到同一节点,然后值保持不变或JComponent用原始值刷新,则会发生什么问题,但这是关于bussines逻辑,而不是关于如何编码,我的推测