1

Cross-posted: https://forums.oracle.com/forums/thread.jspa?threadID=2512538&tstart=0

Hello, everybody.

Is there a way to flush pending AWT events programmatically? I would like to be able to use it in a code like this:

if (comp.requestFocusInWindow())
{
    // flush pending AWT events...
    KeyboardFocusManager focusManager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
    if (focusManager.getPermanentFocusOwner() == comp)
    {
        // do something...
    }
}

Thank you.

Marcos

PS: I know I can use a FocusListener in comp, but it is not an option in my case.

UPDATE:

The essence of my problem is this: to focus the actual editor componente of a JTable before the key that starts the editing is dispatched to it. So I came out with this solution:

private class TextFieldColumnEditor extends MyCustomTextField
{
    // TODO
    private static final long serialVersionUID = 1L;

    private FocusListener _keyDispatcher;

    @Override
    protected boolean processKeyBinding(final KeyStroke ks, final KeyEvent e, int condition, boolean pressed)
    {
        InputMap bindings = getInputMap(condition);
        ActionMap actions = getActionMap();
        if (bindings != null && actions != null && isEnabled())
        {
            Object binding = bindings.get(ks);
            final Action action = binding == null ? null : actions.get(binding);
            if (action != null)
            {
                if (!isFocusOwner() && requestFocusInWindow())
                {
                    // In case something went wrong last time and the
                    // listener wasn't unregistered.
                    removeFocusListener(_keyDispatcher);

                    _keyDispatcher =
                         new FocusListener()
                         {
                             @Override
                             public void focusGained(FocusEvent evt)
                             {
                                 removeFocusListener(this);
                                 SwingUtilities.invokeLater(
                                     new Runnable()
                                     {
                                         @Override
                                         public void run()
                                         {
                                             SwingUtilities.notifyAction(action, ks, e, CampoTextoDadosEditorColuna.this, e.getModifiers());
                                         }
                                     }
                                 );
                             }

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

                    addFocusListener(_keyDispatcher);

                    return true;
                }
                else
                {
                    return SwingUtilities.notifyAction(action, ks, e, this, e.getModifiers());
                }
            }
        }
    return false;
}

The class TextFieldColumnEditor is the componente I use in a custom cell editor. As you can see the solution is not perfect for a lot of reasons:

  • I had to copy the processKeyBinding code from JComponent and change it.
  • I don't know if SwingUtilities.notifyAction had success, because it is executed in another block of code and I can't return it from the processKeyBinding method. I assume it had. That's why I needed some kind of synchronous focus handling.

I'm sticking with this solution for the time being. Your comments and suggestions would be appreciated.

Marcos

UPDATE 2

Final (simplified) version, after suggestion by @VGR:

private class CellEditorTextField extends JTextField
{
    @Override
    protected boolean processKeyBinding(final KeyStroke ks, final KeyEvent e, int condition, boolean pressed)
    {
        InputMap bindings = getInputMap(condition);
        ActionMap actions = getActionMap();
        if (bindings != null && actions != null && isEnabled())
        {
            Object binding = bindings.get(ks);
            final Action action = binding == null ? null : actions.get(binding);
            if (action != null)
            {
                if (e.getSource() == YourJTable.this && action.isEnabled() && requestFocusInWindow())
                {
                    SwingUtilities.invokeLater(
                        new Runnable()
                        {
                            @Override
                            public void run()
                            {
                                SwingUtilities.notifyAction(action, ks, e, CellEditorTextField.this, e.getModifiers());
                            }
                        }
                    );
                    return true;
                }
                else
                {
                    return SwingUtilities.notifyAction(action, ks, e, this, e.getModifiers());
                }
            }
        }
        return false;
    }
}

Comments and improvements are appreciated.

Marcos
  • 1,237
  • 1
  • 15
  • 31
  • no idea, for why reason, but you can to add required Events to the array and every (I'm hope) Swing Listners have got implemented fireXxxXxx, there you can to flush event and with proper ordering – mKorbel Mar 16 '13 at 18:12
  • @mKorbel Could you elaborate a little more? – Marcos Mar 16 '13 at 18:20
  • 2
    As shown [here](http://stackoverflow.com/q/3158254/230513), you can replace the `EventQueue`. The `getNextEvent()` method will remove events, but I don't understand the goal. – trashgod Mar 16 '13 at 19:01
  • @trashgod I'm preparing a little code sample to show you my achievements. I'll read your link after that. – Marcos Mar 16 '13 at 19:05
  • Also consider an [sscce](http://sscce.org/). – trashgod Mar 16 '13 at 19:07
  • 1
    If I understand your goal correctly, executing your FocusManager code in an EventQueue.invokeLater call would work: The code will run after all pending AWT Events have been handled. – VGR Mar 17 '13 at 13:58
  • @VGR That's exactly what I did in the updated code that I posted. I'm using _SwingUtilities.invokeLater_. Have you noticed it? – Marcos Mar 17 '13 at 14:18
  • I see a SwingUtilities.invokeLater in your code, but it's inside a FocusListener. I was suggesting that you could replace your `// flush pending AWT events` comment with `EventQueue.invokeLater` or `SwingUtilities.invokeLater`. By definition, your Runnable would execute after all AWT events are processed. – VGR Mar 17 '13 at 14:23
  • @VGR Ok, I see now. I'm going to give it a try and tell you the results. – Marcos Mar 17 '13 at 14:27
  • @VGR Worked like a charm. I see that my solution, although working, was suffering a little bit from unnecessary complexity. It's a lot simpler now. Thank you. – Marcos Mar 17 '13 at 14:34
  • what are you trying to achieve? Or in other words: _why_ do you want the editor to be focused before it sees the first key stroke? – kleopatra Mar 17 '13 at 15:20
  • @kleopatra Yes, this is another story. It's a requirement of my application. My editor components are some kind of data-aware components linked to some kind of visual dataset and they notify the dataset of a change only if they have the focus. So, when used as a JTable editor, the first character typed did not fire the change notification to the dataset (as the component editor wasn't the focus owner). – Marcos Mar 17 '13 at 15:41
  • thanks for the details :-) Sounds like driving the editors hard at the borderline of their contract: all they are meant to do is notify its listeners when done editing, so notify-while-editing will naturally pose a problem - glad you found a borderline solution – kleopatra Mar 17 '13 at 16:13

0 Answers0