我想创建一个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;
}
首先,默认情况下,通过鼠标按下事件请求对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是否在队列中。这甚至可能比担心使用调用更容易。