Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JTree events seem misordered

It appears to me that tree selection events should happen after focus events, but this doesn't seem to be the case. Assume you have a JTree and a JTextField, where the JTextField is populated by what is selected in the tree. When the user changes the text field, on focus lost, you update the tree from the text field. however, the tree selection is changed before the focus is lost on the text field. this is incorrect, right? Any ideas? Here is some sample code:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

public class Focus extends JFrame
{
 public static void main(String[] args)
 {
  Focus f = new Focus();
  f.setLocationRelativeTo(null);
  f.setVisible(true);
 }

 public Focus()
 {
  Container cp = getContentPane();
  cp.setLayout(new BorderLayout());

  final JTextArea ta = new JTextArea(5, 10);
  cp.add(new JScrollPane(ta), BorderLayout.SOUTH);

  JSplitPane sp = new JSplitPane();
  cp.add(sp, BorderLayout.CENTER);

  JTree t = new JTree();
  t.addTreeSelectionListener(new TreeSelectionListener()
  {
   public void valueChanged(TreeSelectionEvent tse)
   {
    ta.append("Tree Selection changed\n");
   }
  });
  t.addFocusListener(new FocusListener()
  {
   public void focusGained(FocusEvent fe)
   {
    ta.append("Tree focus gained\n");
   }
   public void focusLost(FocusEvent fe)
   {
    ta.append("Tree focus lost\n");
   }
  });

  sp.setLeftComponent(new JScrollPane(t));
  JTextField f = new JTextField(10);
  sp.setRightComponent(f);

  pack();

  f.addFocusListener(new FocusListener()
  {
   public void focusGained(FocusEvent fe)
   {
    ta.append("Text field focus gained\n");
   }
    public void focusLost(FocusEvent fe)
{
    ta.append("Text field focus lost\n");
   }
  });
  setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 }
}
like image 298
MeBigFatGuy Avatar asked Dec 21 '25 07:12

MeBigFatGuy


2 Answers

Have your text field listener invoke setSelectionPath() to select the TreePath for the node that matches the text. The methods of DefaultMutableTreeNode can be used to traverse the tree. I'd use an ActionListener on the text field, but a FocusListener should work—just don't rely on the the order in which TreeSelectionListener events arrive.

Here's an example of obtaining the "pizza" node in the default JTree:

JTree tree = new JTree();
TreeNode node = (TreeNode) tree.getModel().getRoot();
node = node.getChildAt(2).getChildAt(1);
TreePath pizza = new TreePath(((DefaultMutableTreeNode) node).getPath());
like image 162
trashgod Avatar answered Dec 23 '25 22:12

trashgod


Better news: I tried to defer the tree selection logic to the end of EDT, which will be executed after the text field's focus out!

JTree t = new JTree();
t.addTreeSelectionListener(new TreeSelectionListener()
{
   public void valueChanged(TreeSelectionEvent tse)
   {
       ta.append("Tree Selection changed\n");
       SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                logicInEDT...(tse);
            }
       });
    }
});

This solution solved my data binding issue. Hope it make sense to you too.

like image 23
JunLei Avatar answered Dec 23 '25 22:12

JunLei