如何实现自定义DefaultComboBoxModel

时间:2016-03-17 14:39:29

标签: swing jcombobox

我需要实现我的自定义DefaultComboboxModel。这样做的原因是每次我打电话给

DefaultComboBoxModel model = (DefaultComboBoxModel)getModel();
model.removeAllElements();

model.addElement(Object);

model.insertElementAt(Object,int)

我看到它会自动触发ItemStateChanged事件。这导致一些随机项自动从列表中选择。这不是我想要的,因为它使用随机选择的项目填充可编辑的JTextField。

这是我在使用自定义Itemlistener中的Thread.dumpStack()进行调试时看到的堆栈跟踪,我在调用上述方法时看到:

at javax.swing.JComboBox.fireItemStatehanged(Unknown source) 
at javax.swing.JComboBox.selectedItemChanged(Unknown source)
at javax.swing.JComboBox.contentsChanged(Unknown source)
at javax.swing.JComboBox.fireContentsChanged(Unknown source)
at javax.swing.JComboBox.setSelectedItem(Unknown source)
at javax.swing.JComboBox.addElement(Unknown source)

我已经尝试在更新模型之前使用setSelectedIndex(-1),并且在模型更新之后也是如此,但同样的问题。我想让自定义模型成为可行的方法。

问题是如何实现我的自定义组合框模型?我只是扩展DefaultComboBoxModel吗?我是否必须覆盖DefaultComboBoxMode中的所有方法?

以下是我到目前为止的情况。但是,如果您在下面看到,我没有引用实际的矢量列表来删除该项目。如果我在自定义AutocompleteComboBoxModel中声明了一个Vector列表字段,那么我是否需要覆盖所有方法以避免其他SWING代码引用超类中的Vector?

记住我的目标是永远不要让模型自动调用setSelectedItem(Object),因为这似乎会导致问题,除非有更好的方法来做到这一点。

public class AutocompleteComboBoxModel extends DefaultComboBoxModel{

    public void removeElementAt(int index){
        list.removeElementAt(index);
        fireIntervalRemoved(this, index, index);
    }

}

这也是我调用模型操作方法的方法:

public class AutocompleteDocumentListener implementts DocumentListener{
    JTextField tf;

    public AutocompleteDocumentListener (JTextfield tf){
        this.tf = tf;
    }
    @Override
    public void changedUpdate(DocumentEvent e){
    }

    @Override
    public void insertUpdate(DocumentEvent e){
        update();
    }
    @Override
    public void removeUpdate(DocumentEvent e){
       update();
    }

    public void update(){
        SwingUtilities.invokeLater(new Runnable(){
            public void run(){
                performSearch(tf.getText());//Search user input
            }
          )
        }

    }

编辑:只是想提一下,这种奇怪的行为只会在我输入速度非常快时发生。如果我键入慢,那么SWING不会自动选择随机项。那么,如果我使用SwingUtlities.invokeLater,为什么会在快速键入时出现这种情况?目前,当SWING调用setSelectedItem(Object)时,此触发事件是否会在其他invokeLater请求之前执行?

编辑:我正在移除ItemListener但仍无法正常工作。然后我继续去除JComboBox KeyListeners,ActionListeners,ComponentListeners和FocusListeners,它仍然自动选择Item。似乎在invokeLater完成之后的某个时间我看到项目被选中,可能是因为我还在JTextField上输入:

java.lang.Exception: Stack trace
    at java.lang.Thread.dumpStack(Unknown Source)
    at com.artificialmed.coderdx.encoder.TermSelectionListener.itemStateChanged(TermSelectionListener.java:23)
    at javax.swing.JComboBox.fireItemStateChanged(Unknown Source)
    at javax.swing.JComboBox.selectedItemChanged(Unknown Source)
    at javax.swing.JComboBox.contentsChanged(Unknown Source)
    at javax.swing.AbstractListModel.fireContentsChanged(Unknown Source)
    at javax.swing.DefaultComboBoxModel.setSelectedItem(Unknown Source)
    at javax.swing.JComboBox.setSelectedItem(Unknown Source)
    at javax.swing.JComboBox.setSelectedIndex(Unknown Source)
    at javax.swing.JComboBox.selectWithKeyChar(Unknown Source)
    at javax.swing.plaf.basic.BasicComboBoxUI$Handler.keyPressed(Unknown Source)
    at java.awt.Component.processKeyEvent(Unknown Source)
    at javax.swing.JComponent.processKeyEvent(Unknown Source)
    at javax.swing.JComboBox.processKeyEvent(Unknown Source)
    at java.awt.Component.processEvent(Unknown Source)
    at java.awt.Container.processEvent(Unknown Source)
    at java.awt.Component.dispatchEventImpl(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.KeyboardFocusManager.redispatchEvent(Unknown Source)
    at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(Unknown Source)
    at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(Unknown Source)
    at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(Unknown Source)
    at java.awt.DefaultKeyboardFocusManager.dispatchEvent(Unknown Source)
    at java.awt.Component.dispatchEventImpl(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Window.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$200(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)

提前致谢。

1 个答案:

答案 0 :(得分:1)

addElement(...)或insertElementAt(...)方法不应导致生成ItemStateChanged事件,因为选择不应更改。

removeAll()元素会导致所选项目被取消选中,因此生成事件是有意义的。

一些解决方案:

  1. 仅处理所选的"项目"事件。这样当您删除所有项目时,忽略"项目取消选择"事件

  2. 在状态更改代码时调用的逻辑应该调用getSelectedItem()。如果此值为null,则表示您没有做任何事情。

  3. a)删除监听器,b)调用removeAll()方法,c)添加监听器。由于在调用removeAll()方法时侦听器不存在,因此不会生成任何事件。