我们的一位客户在我们的申请中报告了一个例外情况。问题是,我完全无法理解如何重现这个错误。
以下是代码:
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
popup.show(btn, 3, btn.getHeight());
}
});
注意:
btn
是JButton
类型的最终本地变量。popup
是JPopupMenu
类型的最终本地变量。抛出以下异常:
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)
据我了解,show
方法抱怨btn
没有显示。如果btn
方法被调用,actionPerformed
怎么可能没有显示?
此堆栈跟踪中最奇怪的事情是actionPerformed
方法似乎是在处理FocusEvent
时触发的(实际上是focusLost
)。
问题是:你能解释一下这种堆栈跟踪是如何发生的吗?
感谢trashgod的建议,我发现了问题。
在Windows上,当按钮在按下时消失,然后触发其ActionListener ,就像单击按钮一样。这种行为可以在Windows上观察到,但不能在Linux上观察到。
我在Oracle / Sun bug数据库中提交了一个错误。这是链接:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7115421
(此链接将在Java团队审核后的几天内生效。)
感谢您的帮助。来自trashgod和Thomas的答案帮了很多忙。
答案 0 :(得分:6)
一种可能的来源是竞争条件,允许在收件人可见之前触发事件。验证是否在event dispatch thread上构造和操作了仅的Swing GUI对象。 Debugging Swing, the final summary中引用的文章How to generate exceptions from RepaintManager提到了自动搜索的几种方法。
答案 1 :(得分:3)
•btn是JButton类型的最终局部变量。
也许这就是问题所在。也许你有一个在屏幕上看不到的组件的引用。
相反,你应该使用:
JButton button = (JButton)e.getSource();
然后,您确定要引用生成事件的组件。
Alsom确保您没有相同名称的类变量。
答案 2 :(得分:2)
查看DefaultButtonModel#setPressed(...)
的源代码,我们会看到以下内容:
if(!isPressed() && isArmed()) {
...
fireActionPerformed(
new ActionEvent(this, ActionEvent.ACTION_PERFORMED,
getActionCommand(),
EventQueue.getMostRecentEventTime(),
modifiers));
}
正如您所看到的,当按钮处于“布防”状态时,ActionEvent
被触发,即有焦点但没有按下。这与“FocusLost”事件一致。
答案 3 :(得分:0)
改为使用模式特定操作:
final JButton button = new JButton();
button.addMouseListener(new MouseAdapter(){
public void mouseClicked(MouseEvent e) {
popup.show(btn, 3, btn.getHeight());
}
})
答案 4 :(得分:-1)
我无法抗拒,我只能预感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();
}
});
}
}