简体   繁体   English

Java Swing:焦点问题

[英]Java Swing: Focus issue

I'm making a level editor for my game. 我正在为我的游戏制作关卡编辑器。 I have a property panel where I can modify the selected object its properties. 我有一个属性面板,我可以在其中修改所选对象的属性。 I also have a Save button to write the level xml. 我还有一个Save按钮来编写级别xml。

A field-edit is submitted(*) when the editor component lost the focus or Enter is pressed . 当编辑器组件失去焦点按下Enter时,将提交字段编辑(*)。 This is working great, but the only problem is that when I have this sequence of actions: 这很有效,但唯一的问题是,当我有这一系列动作时:

  1. Edit a field 编辑一个字段
  2. Press the save button 按保存按钮

Because, what happens is this: 因为,会发生什么:

  1. I edit the field 我编辑该字段
  2. I press the save button 我按下保存按钮
  3. The level is saved 级别已保存
  4. The field lost the focus 该领域失去了焦点
  5. The edit is submitted 编辑已提交

As you can see, this is the wrong order. 如您所见,这是错误的顺序。 Of course I want the field to lose its focus, which causes the submit and then save the level. 当然我希望该字段失去焦点,这会导致提交然后保存级别。

Is there a trick, hack or workaround to make the field first lose the focus and then perform the action listener of the save button? 是否有技巧,黑客或解决方法使字段首先失去焦点,然后执行保存按钮的动作侦听器?

Thanks in advance. 提前致谢。

(* submit = the edit to the field is also made in the object property) (* submit =字段的编辑也在对象属性中进行)


EDIT : For the field I'm using a FocusAdapter with focusLost : 编辑 :对于我正在使用FocusAdost的focusLost

FocusAdapter focusAdapter = new FocusAdapter()
{

    @Override
    public void focusLost(FocusEvent e)
    {
        compProperties.setProperty(i, getColor());
        record(); // For undo-redo mechanism
    }
};

And for the button a simple ActionListener with actionPerformed`. 对于按钮,一个简单的ActionListener与actionPerformed`。

btnSave.addActionListener(new java.awt.event.ActionListener() {
     public void actionPerformed(java.awt.event.ActionEvent evt) {
         // Save the level
     }
});

Hmm ... can't reproduce: in the snippet below the lost is always notified before the actionPerfomed, independent on whether I click the button or use the mnemonic: 嗯...无法重现:在下面的片段中,丢失的内容总是在actionPerfomed之前得到通知,独立于我是否单击按钮或使用助记符:

    final JTextField field = new JTextField("some text to change");
    FocusAdapter focus = new FocusAdapter() {

        @Override
        public void focusLost(FocusEvent e) {
            LOG.info("lost: " + field.getText());
        }

    };
    field.addFocusListener(focus);

    Action save = new AbstractAction("save") {

        @Override
        public void actionPerformed(ActionEvent e) {
            LOG.info("save: " + field.getText());
        }
    };
    save.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_S);
    JButton button = new JButton(save);
    JComponent box = Box.createHorizontalBox();
    box.add(field);
    box.add(button);

On the other hand, focus is a tricky property to rely on, the ordering might be system-dependent (mine is win vista). 另一方面,焦点是一个难以依赖的属性,排序可能是系统依赖的(我的是胜利视野)。 Check how the snippet behave on yours. 检查代码段在您的代码上的行为方式。

  • If you see the same sequence as I do, the problem is somewhere else 如果您看到与我相同的序列,则问题出在其他地方
  • if you get the save before the lost, try to wrap the the save action into invokeLater (which puts it at the end of the EventQueue, so it's executed after all pending events) 如果你在丢失之前得到了保存,请尝试将save动作包装到invokeLater(它将它放在EventQueue的末尾,因此它在所有挂起的事件之后执行)

     Action save = new AbstractAction("save") { @Override public void actionPerformed(ActionEvent e) { SwingUtilities.invokeLater(new Runnable() { public void run() { LOG.info("save: " + field.getText()); } }); } }; 

Normally, wrapping your save code into an SwingUtilities.invokeLater() should do the trick. 通常,将保存代码包装到SwingUtilities.invokeLater()应该可以解决问题。 As you already mentioned, this doesn't work? 正如您已经提到的,这不起作用? Try this: 尝试这个:

private boolean editFocus = false;
FocusAdapter focusAdapter = new FocusAdapter()
{
   @Override
   public void focusGained(FocusEvent e){
        editFocus = true;
   }
   @Override
   public void focusLost(FocusEvent e){
       compProperties.setProperty(i, getColor());
       record(); // For undo-redo mechanism
       editFocus = false;
       if (saveRequested){
           save();               
       }
   }
};

and for your button: 并为您的按钮:

private boolean saveRequested = false;

btnSave.addActionListener(new java.awt.event.ActionListener() {
    public void actionPerformed(java.awt.event.ActionEvent evt) {
         if (editFocus){
             saveRequested = true;
             return;
         } else {
             save();
         }
    }
});

and then your save method: 然后你的保存方法:

private void save(){
    // do your saving work
    saveRequested = false;
}

This only works when your focusLost gets called after your button's action. 这仅适用于在按钮操作后调用focusLost时。 If suddenly the order is correct, this code will get save() called twice. 如果突然顺序正确,则此代码将调用save()两次。

But again, wrapping your save() code in your original approach should work, because the save code will execute after processing all events. 但同样,在原始方法中包装save()代码应该有效,因为保存代码将在处理完所有事件后执行。 That is after processing your button click and your focusLost events. 这是在处理按钮单击和focusLost事件之后。 Because your focusLost code executes immediately (it's not wrapped in an invokeLater()), the focusLost code should be executed always before your save code. 因为你的focusLost代码立即执行(它没有包装在invokeLater()中),所以应该始终在保存代码之前执行focusLost代码。 This does not mean that the event order will be correct! 这并不意味着事件顺序是正确的! But the code associated to the events will executed in the right order. 但是与事件关联的代码将按正确的顺序执行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM