【问题标题】:how to implement custom DefaultComboBoxModel如何实现自定义 DefaultComboBoxModel
【发布时间】:2016-03-17 14:39:29
【问题描述】:

我需要实现我的自定义 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 代码引用超类中的 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)

提前致谢。

【问题讨论】:

    标签: swing jcombobox


    【解决方案1】:

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

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

    几个解决方案:

    1. 只处理“item selected”事件。这样,当您删除所有项目时,您会忽略“项目取消选择”事件。

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

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

    【讨论】:

    • 不工作。我的 ItemListener 显示状态已更改,我正在检查 (e.getStateChanged == ItemVent.SELECTED)。在这里,dumpstacktrace 显示的内容与我提出的主要问题相同。另外,我正在使用 removeElementAt 删除所有元素。如果我从不删除元素,只是继续添加,那么一切都会按预期进行。这可能是因为我需要使用 DefaultComboBoxModel 来初始化组合框吗?
    • 同样删除我的文档和焦点侦听器也不起作用。
    • 我正在实现我的自定义 MutableComboBoxModel 以查看这是否能解决问题。
    • Also, I'm using removeElementAt to remove all elements. - 为什么? API 提供了一种方法来执行此操作。 Also removing my document and focus listeners did not work. - 重要的是 ItemListener。 Document 和 Focus 侦听器与组合框中的更改选择无关。
    • 还是不行。似乎在 invokeLater 完成后的某个地方,我看到了我刚刚发布的新堆栈跟踪。我在想,在 invokeLater 完成后,模型不是处于有效状态,所以当我以某种方式继续输入时,它会选择一个项目。我想这是一个线程问题。我假设在处理下一个键入的字符之前,在 invokeLater 中触发的所有事件都将具有更高的优先级。
    猜你喜欢
    • 2010-12-02
    • 2016-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-18
    • 2010-11-17
    • 1970-01-01
    相关资源
    最近更新 更多