如何实现自定义 DefaultComboBoxModel

how to implement custom DefaultComboBoxModel

我需要实现我的自定义 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 中的所有方法?

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

中引用 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.access0(Unknown Source)
    at java.awt.EventQueue.run(Unknown Source)
    at java.awt.EventQueue.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain.doIntersectionPrivilege(Unknown Source)
    at java.security.ProtectionDomain.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.run(Unknown Source)
    at java.awt.EventQueue.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain.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)

提前致谢。

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

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

几个解决方案:

  1. 只处理"item selected"事件。这样,当您删除所有项目时,您将忽略 "item deselected" 事件。

  2. 在状态更改时调用的逻辑中,您的代码应该调用 getSelectedItem()。如果这个值为空,那么你什么都不做。

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