The JButton action raises the focusLost event. How is this possible?

One of our customers reported an exception in our application. The problem is that I completely cannot understand how this error can be reproduced.

Here is the code:

btn.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { popup.show(btn, 3, btn.getHeight()); } }); 

Notes:

  • btn is a final local variable of type JButton .
  • popup is the final local variable of type JPopupMenu .

The following exception was thrown:

 java.awt.IllegalComponentStateException: component must be showing on the screen to determine its location at java.awt.Component.getLocationOnScreen_NoTreeLock(Unknown Source) at java.awt.Component.getLocationOnScreen(Unknown Source) at javax.swing.JPopupMenu.show(Unknown Source) at fr.def.iss.vd2.mod_site_watcher_gui.SiteElementPanel$4.actionPerformed(SiteElementPanel.java:117) at javax.swing.AbstractButton.fireActionPerformed(Unknown Source) at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source) at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source) at javax.swing.DefaultButtonModel.setPressed(Unknown Source) at javax.swing.plaf.basic.BasicButtonListener.focusLost(Unknown Source) at java.awt.Component.processFocusEvent(Unknown Source) at java.awt.Component.processEvent(Unknown Source) at java.awt.Container.processEvent(Unknown Source) at java.awt.Component.dispatchEventImpl(Unknown Source) at java.awt.Container.dispatchEventImpl(Unknown Source) at java.awt.Component.dispatchEvent(Unknown Source) at java.awt.KeyboardFocusManager.redispatchEvent(Unknown Source) at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(Unknown Source) at java.awt.DefaultKeyboardFocusManager.dispatchEvent(Unknown Source) at java.awt.Component.dispatchEventImpl(Unknown Source) at java.awt.Container.dispatchEventImpl(Unknown Source) at java.awt.Component.dispatchEvent(Unknown Source) at java.awt.EventQueue.dispatchEventImpl(Unknown Source) at java.awt.EventQueue.access$000(Unknown Source) at java.awt.EventQueue$1.run(Unknown Source) at java.awt.EventQueue$1.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source) at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source) at java.awt.EventQueue$2.run(Unknown Source) at java.awt.EventQueue$2.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source) at java.awt.EventQueue.dispatchEvent(Unknown Source) at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source) at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.pumpEvents(Unknown Source) at java.awt.EventDispatchThread.run(Unknown Source) 

As far as I understand, the show method complains that btn not displayed. How is it possible that btn not displayed when its actionPerformed method is actionPerformed ?

The strangest thing about this stacktrace is that the actionPerformed method seems to fire when FocusEvent (a focusLost ) is focusLost .

The question is: can you explain how this can happen on the stack?

Epilogue

Thanks to the suggestion of trashgod, I found the problem.

On Windows , when a button disappears when it is clicked, then its ActionListeners start as if the button were clicked. This behavior is observed on Windows, but not on Linux.

I registered an error in the Oracle / Sun database. here's a link:

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7115421

(this link will become valid within a few days after it is considered by the Java team).

Thank you for your help. Answers from trashgod and Thomas helped a lot.

+4
source share
5 answers

One possible source is a race condition that allows an event to fire before the recipient is visible. Make sure your Swing GUI objects are designed and created only in the event dispatch thread . The Swing Debugging article , a summary of how to throw exceptions from RepaintManager, mentions several approaches to search automation.

+6
source

β€’ btn is a final local variable of type JButton.

Perhaps this is a problem. Perhaps you have a link to a component that does not appear on the screen.

Instead, you should use:

 JButton button = (JButton)e.getSource(); 

Then you know for sure that you are referencing the component that generated the event.

Alsom make sure you do not have class variables with the same name.

+3
source

Looking at the source code for DefaultButtonModel#setPressed(...) , we see the following:

 if(!isPressed() && isArmed()) { ... fireActionPerformed( new ActionEvent(this, ActionEvent.ACTION_PERFORMED, getActionCommand(), EventQueue.getMostRecentEventTime(), modifiers)); } 

As you can see, a ActionEvent fired when the button was β€œarmed”, i.e. had focus, but was not pressed. This is consistent with the "FocusLost" event.

+2
source

Use a specific action instead:

 final JButton button = new JButton(); button.addMouseListener(new MouseAdapter(){ public void mouseClicked(MouseEvent e) { popup.show(btn, 3, btn.getHeight()); } }) 
0
source

I can not resist, I only prefer PopupFactory

 import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.Timer; import javax.swing.border.EmptyBorder; public class UsePopupFactory { private JFrame frame = new JFrame("PopupFactory Sample"); private PopupFactory factory = PopupFactory.getSharedInstance(); private Popup popup; public UsePopupFactory() { JPanel btnPanel = new JPanel(); btnPanel.setBorder(new EmptyBorder(20, 20, 20, 20)); btnPanel.setLayout(new GridLayout(0, 3)); ActionListener actionListener = new ShowPopup(frame); JButton start3 = new JButton("Pick Me for Popup"); JButton start = new JButton("Pick Me for Popup"); JButton start2 = new JButton("Pick Me for Popup"); btnPanel.add(start3); btnPanel.add(start); btnPanel.add(start2); start3.setVisible(false); start2.setVisible(false); start.addActionListener(actionListener); Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(btnPanel, BorderLayout.SOUTH); frame.setSize(new Dimension(d.width / 4, d.height / 4)); frame.setVisible(true); } private class ShowPopup implements ActionListener { private Component component; ShowPopup(Component component) { this.component = component; } public synchronized void actionPerformed(ActionEvent actionEvent) { JPanel pnl = new JPanel(); JComboBox combo = new JComboBox(); JButton button = new JButton("any action"); pnl.add(combo); pnl.add(button); pnl.setPreferredSize(new Dimension(250, 40)); popup = factory.getPopup(component, pnl, frame.getWidth() / 2 - pnl.getPreferredSize().width / 2, frame.getHeight() / 2 - pnl.getPreferredSize().height / 2); popup.show(); Timer timer = new Timer(3000, hider); timer.start(); } } private Action hider = new AbstractAction() { private static final long serialVersionUID = 1L; @Override public void actionPerformed(ActionEvent e) { popup.hide(); } }; public static void main(final String args[]) { java.awt.EventQueue.invokeLater(new Runnable() { @Override public void run() { UsePopupFactory uPF = new UsePopupFactory(); } }); } } 
-1
source

Source: https://habr.com/ru/post/1382516/


All Articles