jcombobox作为单元格编辑器java.awt.IllegalComponentStateException:必须在屏幕上显示组件以确定其位置

时间:2013-09-23 21:02:07

标签: java swing jtable jcombobox illegalstateexception

我使用自定义JComboBox作为JTable中的单元格编辑器。当用户使用键盘控件进入单元格时,它会尝试打开弹出窗口。这会导致以下错误:

java.awt.IllegalComponentStateException: component must be showing on the screen to determine its location
    at java.awt.Component.getLocationOnScreen_NoTreeLock(Component.java:1964)
    at java.awt.Component.getLocationOnScreen(Component.java:1938)
    at javax.swing.JPopupMenu.show(JPopupMenu.java:887)
    at javax.swing.plaf.basic.BasicComboPopup.show(BasicComboPopup.java:191)
    at javax.swing.plaf.basic.BasicComboBoxUI.setPopupVisible(BasicComboBoxUI.java:859)
    at javax.swing.JComboBox.setPopupVisible(JComboBox.java:796)

我看过一些文章说明这是一个已知问题,解决方法是设置:

    comboBox.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);

然而,这没有帮助。无论如何这应该做什么?

我读到的关于此问题的所有主题和文章对问题的性质都非常模糊。

有没有人对此问题发生原因的性质有任何了解?我的组合框是非常自定义的,所以它有助于理解问题的基础,所以我可以修复代码。

这是在捕获的组合框上的焦点获取事件上触发并调用setPopupVisible(true);

 public void focusGained(java.awt.event.FocusEvent e)
 {
        //if focus is gained then make sure we show the popup if it is suppose to be visible
            setPopupVisible(true);
        //and highlight the selected text if any
        comboTextEditor.setCaretPosition(comboTextEditor.getText().length());
        comboTextEditor.moveCaretPosition(0);
 }

顺便说一下,我在Java 1.7_40中得到与Java 1.6_45相同的结果

完整堆栈跟踪:

Exception in thread "AWT-EventQueue-1" java.awt.IllegalComponentStateException: component must be showing on the screen to determine its location
    at java.awt.Component.getLocationOnScreen_NoTreeLock(Component.java:1964)
    at java.awt.Component.getLocationOnScreen(Component.java:1938)
    at javax.swing.JPopupMenu.show(JPopupMenu.java:887)
    at javax.swing.plaf.basic.BasicComboPopup.show(BasicComboPopup.java:191)
    at javax.swing.plaf.basic.BasicComboBoxUI.setPopupVisible(BasicComboBoxUI.java:859)
    at javax.swing.JComboBox.setPopupVisible(JComboBox.java:796)
    at com.mbs.generic.view.swing.combobox.AutoCompleteComboBox$1.focusGained(AutoCompleteComboBox.java:185)
    at java.awt.AWTEventMulticaster.focusGained(AWTEventMulticaster.java:203)
    at java.awt.Component.processFocusEvent(Component.java:6179)
    at java.awt.Component.processEvent(Component.java:6046)
    at java.awt.Container.processEvent(Container.java:2039)
    at java.awt.Component.dispatchEventImpl(Component.java:4653)
    at java.awt.Container.dispatchEventImpl(Container.java:2097)
    at java.awt.Component.dispatchEvent(Component.java:4481)
    at java.awt.KeyboardFocusManager.redispatchEvent(KeyboardFocusManager.java:1848)
    at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(DefaultKeyboardFocusManager.java:901)
    at java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:513)
    at java.awt.Component.dispatchEventImpl(Component.java:4525)
    at java.awt.Container.dispatchEventImpl(Container.java:2097)
    at java.awt.Component.dispatchEvent(Component.java:4481)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:648)
    at java.awt.EventQueue.access$000(EventQueue.java:84)
    at java.awt.EventQueue$1.run(EventQueue.java:607)
    at java.awt.EventQueue$1.run(EventQueue.java:605)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87)
    at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:98)
    at java.awt.EventQueue$2.run(EventQueue.java:621)
    at java.awt.EventQueue$2.run(EventQueue.java:619)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:618)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

感谢

4 个答案:

答案 0 :(得分:5)

首先,让我解释comboBox.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);的作用。通常,将鼠标悬停在某个项目上或按下键盘上的箭头键将立即选择JComboBox上的项目。由于来自JComboBox的选择事件将导致单元格编辑过程停止,因此此行为不适用于表格单元格。因此,在设置此特殊客户端属性项时,将在弹出列表中选择但未在JComboBox上设置。只有已提交的项目(通过单击或Enter键)将更改JComboBox上的选定项目,然后导致编辑结束。至少,这适用于BasicLookAndFeel及其衍生物。

你遇到的问题完全不同。由于异常消息和堆栈跟踪清楚地说明,外观尝试打开与JPopupMenu相关联的JComboBox(如您所请求的),但它无法确定屏幕上的位置。弹出菜单,因为您的JComboBox未在屏幕上显示。它想要JComboBox的位置的原因是它打开了相对于JComboBox的新窗口。

剩下的问题是,您收到了focusGained中未显示在屏幕上的JComboBox的原因(或者您认为的原因)。

答案 1 :(得分:1)

类似于JComboBox中的下拉列表的弹出窗口往往具有事件处理顺序的边缘情况,因为它们几何上没有嵌套在组件层次结构中的祖先中。在您的情况下,您正在使框的焦点处理程序显示下拉。要做到这一点,它需要盒子已经位于屏幕上,但事实并非如此。

解决方案几乎肯定是推迟显示下拉,直到所有可以使框可见的事件都被处理完毕。我有一个类似的(虽然不完全相同)问题,并能够以这种方式解决它。令人高兴的是,有一个Swing实用程序功能可以解决问题。尝试在invokeLaterRunnable

中包装焦点获取处理程序的主体
void focusGained() {
  SwingUtilities.invokeLater(new Runnable() { 
    ... focus gained body including show of pulldown menu here ... 
  });
}

invokeLater在队列末尾放置一条包含Runnable的新邮件,即在所有现有邮件之后。在处理完所有其他消息之后,Runnable仅在消息到达头部时执行。这正是你想要的。

答案 2 :(得分:0)

我是第二个(第三个?第四个?)每个人都要求使用你的自定义组合框来减少一个表格的例子,可能是组合框本身的一些代码,但无论如何只是为了刺它...您是否尝试制作EditorDelegate的自定义版本以使用其他自定义代码,并将代码显示为focusGained()的代理人startCellEditing()方法?

答案 3 :(得分:-2)

如果您将指令嵌入try .. catch指令中,您的程序将运行没有问题:

SwingUtilities.invokeLater(new Runnable(){

                        public void run()
                        {
                        try {
                        tInput.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);
                        tInput.showPopup();
                        }
                        catch   (IllegalComponentStateException e) {
                                return;
                                }

                          }
                 });