提问者:小点点

JTextField中的高亮文本,但仅在制表符时


我想创建一个JDialog,其中文本字段中的文本被选中,但前提是焦点是从键盘(TAB、CTRLTAB)获得的。我已经找到了几个关于这个问题的主题,但在实现它时遇到了问题。

这是我正在尝试的一个。

还有我的代码:

public class Dialogg extends JDialog implements FocusListener, MouseListener {

private boolean focusFromMouse = false;

public Dialogg() {
    JTextField tf1 = new JTextField("text1");
    JTextField tf2 = new JTextField("text2");

    tf1.addMouseListener(this);
    tf2.addMouseListener(this);
    tf1.addFocusListener(this);
    tf2.addFocusListener(this);
}

@Override
public void focusGained(FocusEvent e) {
    if (!focusFromMouse) {
        JTextField tf = (JTextField) e.getComponent();
        tf.selectAll();
        focusFromMouse = true;
    }
}

@Override
public void focusLost(FocusEvent e) {
    focusFromMouse = false;
}

@Override
public void mouseClicked(MouseEvent e) {
    focusFromMouse = true;
}

}

它没有按预期工作,文本总是突出显示的焦点源并不重要。当我运行代码并一步一步地遵循它时,结果发现焦点获取代码发生在鼠标点击代码之前,因此标志不会在应该重置时重置。有什么提示吗?

编辑:

正如M.普罗霍罗夫所建议的,我已经从代码中删除了不太相关的行。谢谢你。

编辑2:

我正在尝试按照camickr的建议包装焦点侦听器。它现在看起来像这样:

tf1.addFocusListener(new FocusAdapter() {
        public void focusGained(FocusEvent evt){
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                        if (!focusFromMouse){
                        tf1.selectAll();
                        focusFromMouse=true;
                    }                        
                }                
            });
        }
        public void focusLost(FocusEvent evt){
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    focusFromMouse=false;
                }
            });
        }
    });
public void mouseClicked(MouseEvent e) {
        focusFromMouse=true;        

我在每个事件后打印行以查看操作顺序,但鼠标点击仍然发生在最后。我做错了什么?

编辑3:

好的,我找到了一个满足我的简单对话框要求的解决方案。我找不到使用调用EventQueue来做到这一点的方法。Vladislav的方法有效,但据我所知,它限制用户只能使用键盘。我使用了最初的方法,但我添加了一个辅助变量和一些条件,允许通过事件“毫发无损地”传递标志,这些事件在给定时刻不应改变标志。它可能不是微妙的或普遍的,但适用于我的应用程序。以下是代码:

public void focusGained(FocusEvent e) {
    if(!focusFromMouse){
        if (higlight){
           JTextField tf = (JTextField) e.getComponent(); 
           tf.selectAll();
           focusFromMouse=false;    
        }
    }        
}

public void focusLost(FocusEvent e) {
    if (focusFromMouse){
        higlight=false;
        focusFromMouse=false; 
    }else{
        higlight=true;       
    }
}

public void mousePressed(MouseEvent e) {
    focusFromMouse=true;    
}

共2个答案

匿名用户

首先,默认情况下,通过鼠标按下事件请求对JTextField的关注,而不是通过鼠标单击。

所以,这个方法:

public void mouseClicked(MouseEvent e) {
    focusFromMouse = true;
}

是无用的,因为鼠标单击事件是在鼠标按下事件之后触发的。

解决问题的一种方法是从JTextField中删除所有本机MouseListeners:

...
for( MouseListener ml : tf1.getMouseListeners() ){
    tf1.removeMouseListener(ml);
}

for( MouseMotionListener mml : tf1.getMouseMotionListeners() ){
    tf1.removeMouseMotionListener(mml);
}
...

另一种方法是处理所有鼠标事件并使用其中由JTextField触发的事件:

Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
  @Override
  public void eventDispatched(AWTEvent event) {
    if( event.getSource() == tf1 ){
      ((MouseEvent)event).consume();
    }
  }
}, AWTEvent.MOUSE_EVENT_MASK);

匿名用户

当我运行代码并一步一步地遵循它时,事实证明焦点获取代码发生在鼠标点击之前

Focus usListener中的代码包装在SwingU的.调用者()中。这将把代码放在事件调度线程(EDT)的末尾,因此代码将在设置MouseListener中的变量后运行。

有关EDT的更多信息,请参阅Swing中的并发。

编辑:

刚刚注意到另一个答案。你也许可以做一些更简单的事情。不是监听mouseCl的,而是监听mouseP“”。mouseCl“事件”仅在mouseRele“事件”之后生成,因此到那时,即使添加到EDT的末尾,也已经执行了Focus usListener逻辑。

编辑2:

如果上述方法不起作用,那么您可以使用EventQueue. peek()方法来查看MouseEvent是否在队列中。这甚至可能比担心使用调用更容易。