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

jcombobox作为单元格编辑器java.awt.IllegalComponentStateException:组件必须显示在屏幕上才能确定其位置,java,swing,jtable,jcombobox,illegalstateexception,Java,Swing,Jtable,Jcombobox,Illegalstateexception,我在JTable中使用自定义JComboBox作为单元格编辑器。当用户使用键盘控件到达单元格时,它会尝试打开弹出窗口。这会导致以下错误: java.awt.IllegalComponentStateException: component must be showing on the screen to determine its location at java.awt.Component.getLocationOnScreen_NoTreeLock(Component.java:19

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

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)

顺便说一下,我在Java1.7_40中得到的结果与Java1.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)

谢谢

首先,让我解释一下什么是
comboBox.putClientProperty(“JComboBox.isTableCellEditor”,Boolean.TRUE)可以。通常情况下,将鼠标悬停在项目上或按键盘上的箭头键将立即在
JComboBox
上选择项目。由于来自
JComboBox
的选择事件将导致单元格编辑过程停止,因此此行为不适用于表格单元格。因此,在设置此特殊客户端属性时,将在弹出列表中显示选中的项目,但尚未在
JComboBox
上设置。只有提交的项目(通过单击或回车键)才会更改
JComboBox
上的选定项目,从而导致编辑结束。至少,这适用于
BasicLookAndFeel
及其衍生产品

你的问题完全不同。正如异常消息和堆栈跟踪明确指出的那样,look-and-feel尝试打开与
JComboBox
关联的
jpopmpmenu
(根据您的请求),但它无法确定弹出菜单的屏幕位置,因为屏幕上没有显示您的
JComboBox
。它之所以需要
JComboBox
的位置,是因为它打开了相对于
JComboBox
的新窗口


剩下的问题是,为什么您从
JComboBox
收到一个未显示在屏幕上的
focusgound
(或者为什么您认为您收到了).

像JComboBox中的下拉菜单这样的弹出窗口往往具有事件处理顺序的边缘案例,因为它们不是几何嵌套在组件层次结构中的祖先中。在您的例子中,您正在使框的焦点处理程序显示下拉列表。要做到这一点,它需要框已经在屏幕上,但它不是

解决方案几乎肯定是推迟显示下拉列表,直到所有使框可见的事件都处理完毕。我有一个类似的问题(虽然不完全相同),并能够以这种方式解决它。幸运的是,有一个Swing实用程序函数可以实现这一点。尝试在
invokeLater
Runnable
中包装焦点获取处理程序的主体:

void focusGained() {
  SwingUtilities.invokeLater(new Runnable() { 
    ... focus gained body including show of pulldown menu here ... 
  });
}

invokeLater
将包含
Runnable
的新消息放在队列末尾,即在所有现有消息之后。只有在处理完所有其他消息后,当消息到达头部时,才会执行
Runnable
。这正是您想要的。

我是第二个(第三个?第四个?)每个人都要求提供一个使用自定义组合框的表的简化示例,可能是组合框本身的一些代码,但无论如何,只是想尝试一下……如果将指令嵌入try中,您是否尝试过制作自定义版本的以与其他自定义代码配合使用,并将显示弹出窗口的代码从
focusgound()
移动到您代表的
startCellEditing()
方法中?

。。catch指令,您的程序将毫无问题地运行:

SwingUtilities.invokeLater(new Runnable(){

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

                          }
                 }); 

如果我能制作一个简短的复制品,我会发布一个SSCCE,但所涉及的一切都是定制的。然而,这个问题似乎很严重,没有明确的原因或解决方案。您是否试图自己打开组合框的弹出菜单?
,但涉及的一切都是自定义的。
-然后猜猜问题出在哪里?为什么要自定义代码?你的要求是什么?如果我们知道这个要求,也许我们可以提出一个建议。你应该试着写一个SSCCE来检查这是Swing问题还是你的代码问题。@kleopatra我同意SSCCE是好的。但我在做类似的事情之前见过这个堆栈跟踪。我几乎可以肯定,这是一个事件排序问题,可以在编辑器完全初始化后通过调用
setPopupVisible
来解决。这可以通过
SwingUtilities.invokeLater
完成。感谢您的输入,但我在这里没有看到解决方案。当单元格编辑器从键盘获得输入时,就会获得焦点。我认为在将焦点从渲染器完全更改为表中的编辑器之前,它会转移焦点。可能是挥杆的时间安排有问题,但在挥杆发生时,技术上并没有显示出来。@springcorn:但我不明白你为什么要玩焦点事件。Swing表将询问您是否在正确的时间开始单元格编辑。只需覆盖单元格编辑器中的isCellEditable(EventObject)
,单元格编辑器就会简单地包装我的自动完成组合框。AutoCompleteComboBox的正常行为是在获得焦点时打开其弹出窗口,以便向用户提供选择。在所有其他gui非表环境中,这都可以正常工作。因此,当获得焦点时,它就会这样做。根据我的经验,调用isCellEditable有各种原因,如果我尝试在调用时打开弹出窗口,那么调用时通常看不到它。在我看来,真正的问题要追溯到
SwingUtilities.invokeLater(new Runnable(){

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

                          }
                 });