Java JTextField中的Highlight文本,但仅当使用制表符时

Java JTextField中的Highlight文本,但仅当使用制表符时,java,swing,tabs,jtextfield,selectall,Java,Swing,Tabs,Jtextfield,Selectall,我想创建一个JDialog,在这里选择文本字段中的文本,但仅当焦点从键盘获得时(TAB,CTRL+TAB)。我在这个问题上找到了几个话题,但在实施上遇到了问题 这是我一直在尝试的 我的代码是: public class Dialogg extends JDialog implements FocusListener, MouseListener { private boolean focusFromMouse = false; public Dialogg() { JTextFiel

我想创建一个JDialog,在这里选择文本字段中的文本,但仅当焦点从键盘获得时(TAB,CTRL+TAB)。我在这个问题上找到了几个话题,但在实施上遇到了问题

这是我一直在尝试的

我的代码是:

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

它不能按预期工作,无论文本始终突出显示的焦点来源是什么。当我运行代码并一步一步地跟踪它时,结果表明FocusGaund代码发生在MouseClick代码之前,因此标志不会在应该重置时重置。有什么提示吗

编辑:

根据普罗霍罗夫先生的建议,我已经从代码中删除了不太相关的(关于问题)行。谢谢

编辑2:

我正试图按照camickr的建议来包装focus listener。现在看起来是这样的:

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:

好的,我找到了一个满足我的简单对话框要求的解决方案。 我找不到使用
invokeLater
EventQueue
来实现这一点的方法。工作,但据我所知,它限制用户只使用键盘。 我使用了最初的方法,但我添加了一个辅助变量和一些条件,允许通过在给定时刻不应更改标志的事件传递标志“未受伤害”。它可能并不微妙或通用,但适用于我的应用程序。代码如下:

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;    
}
当我运行代码并一步一步地跟踪它时,结果表明FocusGain代码发生在鼠标单击之前

FocusListener
中的代码包装到
SwingUtilities.invokeLater()
中。将把代码放在事件分派线程(EDT)的末尾,因此代码将在设置MouseListener中的变量后运行

有关EDT的更多信息,请参阅

编辑:

我注意到了另一个答案。你也许可以做一些简单的事情。Istead的侦听器已单击
鼠标
,侦听已按下的
鼠标
。mouseClicked事件仅在MouseRelease事件之后生成,因此此时FocusListener逻辑已经执行,即使添加到EDT的末尾也是如此

编辑2:

如果上述方法不起作用,则可以使用
EventQueue.peek()
方法查看队列中是否有MouseEvent。这可能比担心调用器的使用更容易

当我运行代码并一步一步地跟踪它时,结果表明FocusGain代码发生在鼠标单击之前

FocusListener
中的代码包装到
SwingUtilities.invokeLater()
中。将把代码放在事件分派线程(EDT)的末尾,因此代码将在设置MouseListener中的变量后运行

有关EDT的更多信息,请参阅

编辑:

我注意到了另一个答案。你也许可以做一些简单的事情。Istead的侦听器已单击
鼠标
,侦听已按下的
鼠标
。mouseClicked事件仅在MouseRelease事件之后生成,因此此时FocusListener逻辑已经执行,即使添加到EDT的末尾也是如此

编辑2:


如果上述方法不起作用,则可以使用
EventQueue.peek()
方法查看队列中是否有MouseEvent。这可能比担心使用invokeLater更容易。

首先,默认情况下,焦点在JTextField上是由鼠标按下事件而不是鼠标单击请求的

因此,这种方法:

public void mouseClicked(MouseEvent e) {
    focusFromMouse = true;
}
无效,因为鼠标单击事件是在鼠标按下事件之后触发的

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

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

for( MouseMotionListener mml : tf1.getMouseMotionListeners() ){
    tf1.removeMouseMotionListener(mml);
}
...
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
  @Override
  public void eventDispatched(AWTEvent event) {
    if( event.getSource() == tf1 ){
      ((MouseEvent)event).consume();
    }
  }
}, AWTEvent.MOUSE_EVENT_MASK);
另一种方法是处理所有鼠标事件并使用这些事件,这些事件由JTextField触发:

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

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

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

因此,这种方法:

public void mouseClicked(MouseEvent e) {
    focusFromMouse = true;
}
无效,因为鼠标单击事件是在鼠标按下事件之后触发的

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

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

for( MouseMotionListener mml : tf1.getMouseMotionListeners() ){
    tf1.removeMouseMotionListener(mml);
}
...
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
  @Override
  public void eventDispatched(AWTEvent event) {
    if( event.getSource() == tf1 ){
      ((MouseEvent)event).consume();
    }
  }
}, AWTEvent.MOUSE_EVENT_MASK);
另一种方法是处理所有鼠标事件并使用这些事件,这些事件由JTextField触发:

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

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

我认为您可以安全地减少这个问题中的代码量,而不会失去它的意义。例如,仅使用单个面板作为示例,并跳过所有空侦听器方法。这样我们就更容易看到发生了什么,这意味着我们更容易帮助你。另请注意,如果您正在寻找提示,那么唯一实际存在的就是事件的
paramString
。试着检查一下,也许会有帮助。@M.Prokhorov:你测试过paramString了吗?为什么会有这个建议?@hoverfullofeels,不,我没有。这只是在黑暗中拍摄,老实说,我不认为Swing的设计者特别有兴趣在活动背景下提供此类信息,因此可能根本不可用,或者作为框架本身内部某些本地上下文对象的一部分提供。@M.Prokhorov:我可以告诉您,
paramString
不会保存帮助OP的信息,但我同意您的观点,库不是为了轻松提取这些信息而构建的。我不知道是否存在相当大的混乱,主要是因为我的程序都不需要这个功能。我认为你可以安全地减少这个问题中的代码量,而不会失去它的意义。例如,仅使用单个面板作为示例,并跳过所有空侦听器方法。这样我们就更容易看到发生了什么,这意味着我们更容易帮助你。另请注意,如果您正在寻找提示,那么唯一实际存在的就是事件的
paramString