我想创建一个JDialog,其中文本字段中的文本被选中,但只有从键盘获得焦点(TAB,CTRL + TAB)。我在这个问题上找到了几个主题但是在实现它时遇到了问题。
Here是我正在尝试的。
我的代码:
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;
}
}
它不能按预期工作,文本总是突出显示的焦点源是什么并不重要。当我运行代码并逐步遵循它时,事实证明focusGained代码发生在mouseClicked代码之前,因此标志不应该重置。任何提示?
修改
正如M. Prokhorov所建议的那样,我从代码中删除了较少相关(问题)的行。谢谢。
编辑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;
我在每个事件之后打印行以查看操作顺序并且仍然发生mouseClicked最后发生。我做错了什么?
编辑3:
好的,我找到了一个满足我简单Dialog要求的解决方案。
我使用invokeLater
或EventQueue
找不到这样做的方法。 Vladislav's method有效,但据我了解,它限制用户仅使用键盘。
我已经使用了初始方法但是我添加了一个辅助变量和一些条件允许传递旗帜"没有受到伤害" trough在给定时刻不应更改标志的事件。它可能不是微妙或通用但适用于我的应用程序。这是代码:
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;
}
答案 0 :(得分:1)
当我运行代码并逐步跟踪它时,发现focusGained代码在mouseClicked之前发生
将FocusListener
中的代码包裹在SwingUtilities.invokeLater()
中。将代码放在事件调度线程(EDT)的末尾,因此代码将在设置了MouseListener中的变量后运行。
有关EDT的详细信息,请参阅Concurrency in Swing。
编辑:
注意到另一个答案。你或许可以做一些更简单的事情。 mouseClicked
的倾听者,请听mousePressed
。 mouseClicked事件仅在mouseReleased事件之后生成,因此到那时FocusListener逻辑已经被执行,即使被添加到EDT的末尾也是如此。
编辑2:
如果上述方法无效,那么您可以使用EventQueue.peek()
方法查看MouseEvent是否在队列中。这可能比担心使用invokeLater更容易。
答案 1 :(得分:1)
首先,默认情况下,鼠标按下事件请求关注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);
}
...
另一种方法是处理所有鼠标事件并使用它们,这些事件由JTextField触发:
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
@Override
public void eventDispatched(AWTEvent event) {
if( event.getSource() == tf1 ){
((MouseEvent)event).consume();
}
}
}, AWTEvent.MOUSE_EVENT_MASK);