【问题标题】:JTree events seem misorderedJTree 事件似乎顺序错误
【发布时间】:2010-04-27 01:24:53
【问题描述】:

在我看来,树选择事件应该在焦点事件之后发生,但事实并非如此。假设您有一个 JTree 和一个 JTextField,其中 JTextField 由树中选择的内容填充。当用户更改文本字段时,失去焦点时,您从文本字段更新树。但是,在文本字段上失去焦点之前,树选择会发生变化。这是不正确的,对吧?有任何想法吗?下面是一些示例代码:

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);
 }
}

【问题讨论】:

  • 你永远不应该根据事件的顺序编写代码。
  • 您应该在事件调度线程上构建 GUI:java.sun.com/docs/books/tutorial/uiswing/concurrency/…
  • 我同意你的观点:如果在树选择事件之前触发焦点事件会更合乎逻辑。
  • 所以我不应该假设 windowClosing 事件将在 windowClosed 事件之前发生?有趣...
  • 已经有一段时间了,但无法抗拒:我不应该假设 windowClosing 事件将在 windowClosed 事件之前 - 多么愚蠢的评论,除非假设你没有't read the doc ;-)

标签: java swing events jtree


【解决方案1】:

让您的文本字段侦听器调用 setSelectionPath() 以选择与文本匹配的节点的 TreePath。可以使用DefaultMutableTreeNode 的方法来遍历树。我会在文本字段上使用ActionListener,但FocusListener 应该可以工作——只是不要依赖TreeSelectionListener 事件到达的顺序。

下面是在默认JTree中获取“pizza”节点的例子:

JTree tree = new JTree();
TreeNode node = (TreeNode) tree.getModel().getRoot();
node = node.getChildAt(2).getChildAt(1);
TreePath pizza = new TreePath(((DefaultMutableTreeNode) node).getPath());

【讨论】:

  • 不,你误会了,也许我没有解释。无论用户在文本字段中输入什么,在失去焦点时,都应该更改当前选择的树节点。
  • IIUC, setSelectionPath() 在从 focusLost() 调用时会执行此操作:它将选择更改为指定的 TreePath。如果您正在尝试编辑节点,使用t.setEditable(true) 可能更容易;这将允许原位编辑
  • 文本字段可能会显示“fooo”,但树中没有 fooo。事实上,它甚至可能不是正在更改的节点标签——它可能只是所选节点的用户对象中的一个字段。
  • 在遍历树时检查每个用户对象似乎很容易。我通常在失败时返回 null;当传递给setSelectionPath() 时,null 清除选择。
【解决方案2】:

更好的消息:我尝试将树选择逻辑推迟到 EDT 的末尾,这将在文本字段的焦点移出后执行!

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);
            }
       });
    }
});

此解决方案解决了我的数据绑定问题。希望它对你也有意义。

【讨论】:

    【解决方案3】:

    坏消息:当我选择另一个树节点时,我遇到了同样的问题。选择您的文本字段正在编辑的同一个树节点就可以了。

    好消息:我发现这个问题真的很老了。看 http://java.net/jira/browse/BINDING-67

    【讨论】:

    • 您所说的根本原因是 TreeSelectionEvent 在焦点丢失/获得事件之前触发。我用 JTable 和 JList 进行了测试,它们都工作正常,我的意思是,选择事件在文本字段失去焦点后触发。
    • 如果你在使用一些数据绑定框架,我不得不说,对于文本字段的承诺,使用 MODIFY 代替 FOCUS_OUT 可能会更好。无论如何,我暂时必须寻求这个解决方案。抱歉,无法提供更多帮助,因为到目前为止我发现的只有这些。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-27
    • 1970-01-01
    • 1970-01-01
    • 2020-12-22
    • 1970-01-01
    • 2011-01-05
    • 2011-05-06
    相关资源
    最近更新 更多