如何使用JComboBox单元格编辑器修复JTable的java.awt.CollectionComponentStat



我需要为表的每一行显示动态数据集,所以我使用DefaultCellEditor(JComboBox)并使用PopupMenuListener将数据加载到他的DefaultComboBoxModel中。我的问题是:当我点击表格的一个单元格时,JComboBox不会显示弹出列表,应用程序会抛出异常。我使用Java 7。

如何修复?

代码示例:

import javax.swing.DefaultCellEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
public class TestTable extends JFrame implements PopupMenuListener
{
    public TestTable()
    {
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        String[] data = new String[]{"A", "B"};        
        DefaultTableModel mdlTable = new DefaultTableModel();
        mdlTable.addColumn("Col");
        for (int i = 0; i < 3; i++) {
            mdlTable.addRow(data);
        }
        JTable tbl = new JTable(mdlTable);
        TableColumnModel mdlColumn = tbl.getColumnModel();
        TableColumn clm = mdlColumn.getColumn(0);
        DefaultComboBoxModel mdlComboBox = new DefaultComboBoxModel();
        JComboBox cmb = new JComboBox(mdlComboBox);
        cmb.addPopupMenuListener(this);
        clm.setCellEditor(new DefaultCellEditor(cmb));
        setContentPane(new JScrollPane(tbl));
        setSize(200, 200);
        setVisible(true);
    }
    @Override
    public void popupMenuWillBecomeVisible(PopupMenuEvent e)
    {
        JComboBox cmb = (JComboBox) e.getSource();
        DefaultComboBoxModel mdl = (DefaultComboBoxModel) cmb.getModel();
        mdl.removeAllElements();
        String[] data = new String[]{"A", "B", "C", "D"};
        for (String item : data) {
            mdl.addElement(item);
        }
    }
    @Override
    public void popupMenuWillBecomeInvisible(PopupMenuEvent e)
    {
    }
    @Override
    public void popupMenuCanceled(PopupMenuEvent e)
    {
    }
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                new TestTable();
            }
        });
    }
}

全栈跟踪:

Exception in thread "AWT-EventQueue-0" java.awt.IllegalComponentStateException: component must be showing on the screen to determine its location
    at java.awt.Component.getLocationOnScreen_NoTreeLock(Component.java:2048)
    at java.awt.Component.getLocationOnScreen(Component.java:2022)
    at javax.swing.JPopupMenu.show(JPopupMenu.java:942)
    at javax.swing.plaf.basic.BasicComboPopup.show(BasicComboPopup.java:208)
    at javax.swing.plaf.basic.BasicComboPopup.togglePopup(BasicComboPopup.java:1128)
    at javax.swing.plaf.basic.BasicComboPopup$Handler.mousePressed(BasicComboPopup.java:825)
    at java.awt.Component.processMouseEvent(Component.java:6513)
    at javax.swing.JComponent.processMouseEvent(JComponent.java:3321)
    at java.awt.Component.processEvent(Component.java:6281)
    at java.awt.Container.processEvent(Container.java:2229)
    at java.awt.Component.dispatchEventImpl(Component.java:4872)
    at java.awt.Container.dispatchEventImpl(Container.java:2287)
    at java.awt.Component.dispatchEvent(Component.java:4698)
    at javax.swing.plaf.basic.BasicTableUI$Handler.repostEvent(BasicTableUI.java:948)
    at javax.swing.plaf.basic.BasicTableUI$Handler.adjustSelection(BasicTableUI.java:1110)
    at javax.swing.plaf.basic.BasicTableUI$Handler.mousePressed(BasicTableUI.java:1038)
    at java.awt.AWTEventMulticaster.mousePressed(AWTEventMulticaster.java:280)
    at java.awt.Component.processMouseEvent(Component.java:6513)
    at javax.swing.JComponent.processMouseEvent(JComponent.java:3321)
    at java.awt.Component.processEvent(Component.java:6281)
    at java.awt.Container.processEvent(Container.java:2229)
    at java.awt.Component.dispatchEventImpl(Component.java:4872)
    at java.awt.Container.dispatchEventImpl(Container.java:2287)
    at java.awt.Component.dispatchEvent(Component.java:4698)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4832)
    at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4489)
    at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4422)
    at java.awt.Container.dispatchEventImpl(Container.java:2273)
    at java.awt.Window.dispatchEventImpl(Window.java:2719)
    at java.awt.Component.dispatchEvent(Component.java:4698)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:740)
    at java.awt.EventQueue.access$300(EventQueue.java:103)
    at java.awt.EventQueue$3.run(EventQueue.java:699)
    at java.awt.EventQueue$3.run(EventQueue.java:697)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87)
    at java.awt.EventQueue$4.run(EventQueue.java:713)
    at java.awt.EventQueue$4.run(EventQueue.java:711)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:710)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)

一个简单的解决方法是更改模型,而不是在现有模型中添加元素:

@Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e)
{
    JComboBox<String> cmb = (JComboBox<String>) e.getSource();
    cmb.setModel(new DefaultComboBoxModel<>(new String[]{"A", "B", "C", "D"}));
}

最新更新