如何实现自定义默认组合框模型



我需要实现我的自定义 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 吗?我是否必须覆盖默认组合框模式中的所有方法?

以下是我到目前为止所拥有的。 但是,如果您在下面看到,我没有参考实际的 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 请求之前执行?

编辑:我正在删除项目侦听器,但仍然无法正常工作。然后我继续前进并删除了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)

提前谢谢。

addElement(...)

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

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

几个解决方案:

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

  2. 在状态更改时调用的逻辑中,代码应该调用 getSelectedItem()。如果此值为 null,则不执行任何操作。

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

最新更新