自定义JComboBox:当LAF是系统LAF时,“无限循环事件”

我自定义我的JComboBox如下。 程序在默认LAF下运行正常,但每当我将LAF更改为系统LAF(另一个LAF,Nimbus,没问题)时,点击按钮后会出现无限循环。 我看到actionPerformed方法被无限调用。
请帮我解决这个问题。 我用的是jdk 1.6.0_33
如果有任何不明确的意思,我很抱歉。 我英文不太好
提前致谢。

package sig.dw.ui; import java.awt.Component; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.ComboBoxEditor; import javax.swing.DefaultComboBoxModel; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JPanel; //import javax.swing.event.EventListenerList; /** * * @author congnh */ public class ButtonableComboBox extends JComboBox{ private ButtonableComboBoxEditor comboBoxEditor; public ButtonableComboBox(){ super(); comboBoxEditor = new ButtonableComboBoxEditor(); // eventListenerList = new EventListenerList(); setEditable(true); setEditor(comboBoxEditor); } public ButtonableComboBox(Object[] items){ this(); setModel(new DefaultComboBoxModel(items)); } public void addButtonListener(ActionListener listener){ comboBoxEditor.addActionListener(listener); } public void removeButtonListener(ActionListener listener){ comboBoxEditor.removeActionListener(listener); } class ButtonableComboBoxEditor implements ComboBoxEditor{ private JButton button; public ButtonableComboBoxEditor(){ button = new JButton(); } @Override public Component getEditorComponent() { return button; } @Override public void setItem(Object anObject) { if(anObject!=null){ button.setText(anObject.toString()); } } @Override public Object getItem() { return button.getText(); } @Override public void selectAll() { throw new UnsupportedOperationException("Not supported yet."); } @Override public void addActionListener(ActionListener l) { System.out.println("add new listener"); button.addActionListener(l); } @Override public void removeActionListener(ActionListener l) { button.removeActionListener(l); } } public static void main(String args[]){ javax.swing.SwingUtilities.invokeLater(new Runnable(){ @Override public void run(){ String[] comboBoxItems = {"Browse","Explorer","Firefox","IE","Chrome","Opera"}; JFrame frame = new JFrame(); JPanel panel = new JPanel(); panel.setLayout(new FlowLayout()); ButtonableComboBox bcb = new ButtonableComboBox(comboBoxItems); bcb.addButtonListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println(e.getActionCommand()); } }); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); panel.add(bcb); frame.add(panel); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } } 

作为参考,我在Mac OS X / Java MotifLookAndFeel上看到了MotifLookAndFeel StackOverflowError ,但没有MetalLookAndFeelNimbusLookAndFeelAquaLookAndFeel 。 使用下面的例子和这里看到的L&F选择器,我得到了下面的堆栈跟踪,因为UI委托以递归方式调用doClick() 。 我没有看到明显的解决方法。

附录:我在Ubuntu 12 / Java 1.6.0_24上看到类似的MotifLookAndFeel StackOverflowError ,但不是MetalLookAndFeelNimbusLookAndFeelGTKLookAndFeel

线程“AWT-EventQueue-0”java.lang.StackOverflowError中的exception
   at sun.font.FontManager.getFont2D(Native Method)
   at sun.java2d.SunGraphics2D.checkFontInfo(SunGraphics2D.java:780)
   at sun.java2d.SunGraphics2D.getFontInfo(SunGraphics2D.java:941)
   at sun.java2d.pipe.GlyphListPipe.drawString(GlyphListPipe.java:32)
   at sun.java2d.SunGraphics2D.drawString(SunGraphics2D.java:3054)
   at sun.swing.SwingUtilities2.drawString(SwingUtilities2.java:517)
   at sun.swing.SwingUtilities2.drawStringUnderlineCharAt(SwingUtilities2.java:538)
  在javax.swing.plaf.basic.BasicButtonUI.paintText(BasicButtonUI.java:294)
  在javax.swing.plaf.basic.BasicButtonUI.paintText(BasicButtonUI.java:319)
  在javax.swing.plaf.basic.BasicButtonUI.paint(BasicButtonUI.java:207)
  在com.sun.java.swing.plaf.motif.MotifButtonUI.paint(MotifButtonUI.java:91)
  在javax.swing.plaf.ComponentUI.update(ComponentUI.java:153)
  在javax.swing.JComponent.paintComponent(JComponent.java:760)
  在javax.swing.JComponent.paint(JComponent.java:1037)
  在javax.swing.JComponent.paintChildren(JComponent.java:870)
  在javax.swing.JComponent.paint(JComponent.java:1046)
  在javax.swing.JComponent.paintChildren(JComponent.java:870)
  在javax.swing.JComponent.paint(JComponent.java:1046)
  在javax.swing.JComponent._paintImmediately(JComponent.java:5106)
  在javax.swing.JComponent.paintImmediately(JComponent.java:4890)
  在javax.swing.JComponent.paintImmediately(JComponent.java:4902)
  在javax.swing.AbstractButton.doClick(AbstractButton.java:352)
  在javax.swing.plaf.basic.BasicRootPaneUI $ Actions.actionPerformed(BasicRootPaneUI.java:191)
  在javax.swing.plaf.basic.BasicComboBoxUI $ Actions.actionPerformed(BasicComboBoxUI.java:1575)
  在javax.swing.plaf.basic.BasicComboBoxUI $ Handler.actionPerformed(BasicComboBoxUI.java:1904)
  在javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2028)
  在javax.swing.AbstractButton $ Handler.actionPerformed(AbstractButton.java:2351)
  在javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
  在javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
  在javax.swing.AbstractButton.doClick(AbstractButton.java:389)
   ...
  在javax.swing.plaf.basic.BasicRootPaneUI $ Actions.actionPerformed(BasicRootPaneUI.java:191)
  在javax.swing.plaf.basic.BasicComboBoxUI $ Actions.actionPerformed(BasicComboBoxUI.java:1575)
  在javax.swing.plaf.basic.BasicComboBoxUI $ Handler.actionPerformed(BasicComboBoxUI.java:1904)
  在javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2028)
  在javax.swing.AbstractButton $ Handler.actionPerformed(AbstractButton.java:2351)
  在javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
  在javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
  在javax.swing.AbstractButton.doClick(AbstractButton.java:389)
  在javax.swing.plaf.basic.BasicRootPaneUI $ Actions.actionPerformed(BasicRootPaneUI.java:191)
  在javax.swing.plaf.basic.BasicComboBoxUI $ Actions.actionPerformed(BasicComboBoxUI.java:1575)

SSCCE:

 import java.awt.BorderLayout; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.List; import javax.swing.ComboBoxEditor; import javax.swing.DefaultComboBoxModel; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JToolBar; import javax.swing.SwingUtilities; import javax.swing.UIManager; public class ButtonableComboBox extends JComboBox { private ButtonableComboBoxEditor comboBoxEditor; public ButtonableComboBox() { comboBoxEditor = new ButtonableComboBoxEditor(); setEditor(comboBoxEditor); setEditable(true); } public ButtonableComboBox(Object[] items) { this(); setModel(new DefaultComboBoxModel(items)); } public void addButtonListener(ActionListener listener) { comboBoxEditor.addActionListener(listener); } public void removeButtonListener(ActionListener listener) { comboBoxEditor.removeActionListener(listener); } class ButtonableComboBoxEditor implements ComboBoxEditor { private JButton button = new JButton(); @Override public Component getEditorComponent() { return button; } @Override public void setItem(Object anObject) { if (anObject != null) { button.setText(anObject.toString()); } } @Override public Object getItem() { return button.getText(); } @Override public void selectAll() { System.out.println("select all"); button.requestFocus(); } @Override public void addActionListener(ActionListener l) { System.out.println("add listener"); button.addActionListener(l); } @Override public void removeActionListener(ActionListener l) { System.out.println("remove listener"); button.removeActionListener(l); } } public static void main(String args[]) { javax.swing.SwingUtilities.invokeLater(new Runnable() { @Override public void run() { String[] comboBoxItems = { "Browse", "Explorer", "Firefox", "IE", "Chrome", "Opera"}; JFrame frame = new JFrame(); JPanel panel = new JPanel(); ButtonableComboBox bcb = new ButtonableComboBox(comboBoxItems); bcb.addButtonListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println(e.getActionCommand()); } }); panel.add(bcb); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // https://stackoverflow.com/a/11949899/230513 frame.add(createToolBar(frame), BorderLayout.NORTH); frame.add(panel); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } }