我需要为表的每一行显示动态数据集,所以我使用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"}));
}