我能否开发一个可编辑的JComboBox的动态下拉框,在用户输入或删除文本时根据输入动态更新内容?
我在用Java 17设置 JComboBox 的弹出框时遇到了一些问题。我在使用WindowBuilder开发我的应用,我希望弹出框在用户输入或删除文本时能更新,只显示与用户输入的文本相匹配的项。若字符串为空,弹出框会显示在原始菜单中;在所有情况下,菜单都可见。为此,我尝试在我的 comboBox 中通过 setModel() 方法来修改模型,在 JcomboBox 的内部的 jTextField 中放入一个 DocumentListener(我称它为editor),但出现了异常:
"Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Attempt to mutate in notification"
首先,我想去查我的老师/导师的指南,但没有关于动态 JcomboBox 的示例。我也在其他论坛上搜索过,甚至在这个论坛里,唯一能做的就是尝试用 MutableComboBoxModel,但连在Java中加载都失败,即使使用快捷键 Ctrl + shift + O(我使用 Eclipse)。我还尝试观看YouTube视频,但没有类似的内容。如果你能帮忙,我将不胜感激,我现在正在使用 Windows 11,
以下是代码,位于 prove.java 文档中。
错误的跟踪和代码如下(无论是在点击 JcomboBox 还是在编辑 comboBox 时都会出现错误):
Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Attempt to mutate in notification
at java.desktop/javax.swing.text.AbstractDocument.writeLock(AbstractDocument.java:1372)
at java.desktop/javax.swing.text.AbstractDocument.replace(AbstractDocument.java:688)
at java.desktop/javax.swing.text.JTextComponent.setText(JTextComponent.java:1725)
at java.desktop/javax.swing.plaf.metal.MetalComboBoxEditor$1.setText(MetalComboBoxEditor.java:63)
at java.desktop/javax.swing.plaf.basic.BasicComboBoxEditor.setItem(BasicComboBoxEditor.java:93)
at java.desktop/javax.swing.JComboBox.configureEditor(JComboBox.java:1439)
at java.desktop/javax.swing.plaf.basic.BasicComboBoxUI$Handler.propertyChange(BasicComboBoxUI.java:1812)
at java.desktop/javax.swing.plaf.basic.BasicComboBoxUI$PropertyChangeHandler.propertyChange(BasicComboBoxUI.java:704)
at java.desktop/javax.swing.plaf.metal.MetalComboBoxUI$MetalPropertyChangeListener.propertyChange(MetalComboBoxUI.java:224)
at java.desktop/java.beans.PropertyChangeSupport.fire(PropertyChangeSupport.java:343)
at java.desktop/java.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:335)
at java.desktop/java.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:268)
at java.desktop/java.awt.Component.firePropertyChange(Component.java:8717)
at java.desktop/javax.swing.JComboBox.setModel(JComboBox.java:362)
at cfgs.prove$3.removeUpdate(prove.java:136)
at java.desktop/javax.swing.text.AbstractDocument.fireRemoveUpdate(AbstractDocument.java:285)
at java.desktop/javax.swing.text.AbstractDocument.handleRemove(AbstractDocument.java:652)
at java.desktop/javax.swing.text.AbstractDocument.remove(AbstractDocument.java:620)
at java.desktop/javax.swing.text.AbstractDocument.replace(AbstractDocument.java:696)
at java.desktop/javax.swing.text.JTextComponent.setText(JTextComponent.java:1725)
at java.desktop/javax.swing.plaf.metal.MetalComboBoxEditor$1.setText(MetalComboBoxEditor.java:63)
at cfgs.prove$4.mousePressed(prove.java:156)
at java.desktop/java.awt.AWTEventMulticaster.mousePressed(AWTEventMulticaster.java:288)
at java.desktop/java.awt.Component.processMouseEvent(Component.java:6618)
at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3398)
at java.desktop/java.awt.Component.processEvent(Component.java:6386)
at java.desktop/java.awt.Container.processEvent(Container.java:2266)
at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:4996)
at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2324)
at java.desktop/java.awt.Component.dispatchEvent(Component.java:4828)
at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4948)
at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4572)
at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4516)
at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2310)
at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2780)
at java.desktop/java.awt.Component.dispatchEvent(Component.java:4828)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:775)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:720)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:714)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:87)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:98)
at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:747)
at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:745)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:87)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:744)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
package cfgs;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import java.awt.Font;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.regex.Pattern;
import javax.swing.JComboBox;
import javax.swing.DefaultComboBoxModel;
public class prove extends JFrame {
private static final long serialVersionUID = 1L;
private JPanel contentPane;
protected JComboBox<String> comboBox;
protected static String[] usuarios = {"James", "Ana", "Andres", "Maria", "John", "gustavo"};
protected static DefaultComboBoxModel<String> comb;
public static String[] FiltrarUsuarios(String str) {
int i = 1, N = usuarios.length;
ArrayList<String> filtrados = new ArrayList<String>();
Pattern filtro = Pattern.compile("^"+str+".*"); //coincide con lo que empieza con este string (str).
comb = new DefaultComboBoxModel<String>(usuarios);
String elemento;
String[] retorno;
while (i<N) {
elemento = comb.getElementAt(i);
if (filtro.matcher(elemento).matches()) //colocar el objeto
filtrados.add(elemento);
i++;
}
N = filtrados.size();
i = 1; //reutilizo ambas variables i, N.
retorno = new String[++N];
retorno[0] = str;
while (i<N) {
retorno[i] = filtrados.get(i-1);
i++;
}
return retorno;
}
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
prove frame = new prove("Introduzca el usuario", true);
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public prove(String mensaje, boolean bool) {
comb = new DefaultComboBoxModel<String>(usuarios);
setTitle("Dynamic comboBox.");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
JLabel lblNewLabel = new JLabel("Dynamic JComboBox");
lblNewLabel.setFont(new Font("Tahoma", Font.BOLD, 17));
lblNewLabel.setHorizontalAlignment(SwingConstants.CENTER);
lblNewLabel.setBounds(116, 11, 184, 39);
contentPane.add(lblNewLabel);
JLabel a_message = new JLabel(mensaje);
a_message.setHorizontalAlignment(SwingConstants.CENTER);
a_message.setFont(new Font("Tahoma", Font.BOLD, 14));
a_message.setBounds(116, 83, 184, 39);
contentPane.add(a_message);
JComboBox<String> comboBox = new JComboBox<String>();
comboBox.setModel(new DefaultComboBoxModel<String>(usuarios));
comboBox.setVisible(bool);
comboBox.setModel(comb);
comboBox.setEditable(true);
comboBox.setFont(new Font("Tahoma", Font.BOLD, 13));
comboBox.addFocusListener(new FocusAdapter() {
@Override
public void focusLost(FocusEvent e) {
new DefaultComboBoxModel<String>(usuarios);
comboBox.setModel(comb);
comboBox.setPopupVisible(false);
}
});
JTextField editor = (JTextField) comboBox.getEditor().getEditorComponent(); //hecho un casteo a Jtextfield para acceder al contenido con el método getText().
editor.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
String src = editor.getText();
String[] lista;
System.out.println("el contenido es:"+src);
lista = FiltrarUsuarios(src);
comb = new DefaultComboBoxModel<String>(lista); //usuarios
comboBox.setModel(comb);
comboBox.setPopupVisible(false);
}
@Override
public void removeUpdate(DocumentEvent e) {
String src = editor.getText();
String[] lista;
System.out.println("Ahora es borrar contenido. El contenido es:"+src);
if (src.equals("")) {
comb = new DefaultComboBoxModel<String>(usuarios);
comboBox.setModel(comb);
comboBox.setPopupVisible(false);
} else {
lista = FiltrarUsuarios(src);
comb = new DefaultComboBoxModel<String>(lista); //usuarios
comboBox.setModel(comb);
comboBox.setPopupVisible(false);
}
}
@Override
public void changedUpdate(DocumentEvent e) {
System.out.println("Formato cambiado");
}
});
editor.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
editor.setText("");
}
});
comboBox.setBounds(116, 133, 184, 39);
contentPane.add(comboBox);
}
}
解决方案
似乎问题产生了 comboBox.setModel(comb);,因为它是在 DocumentListener() 内执行,而对模型的“更改”可能会生成另一个事件,该事件会再次执行另一个 Listener,并且它会尝试再运行一个 comboBox.setModel(comb);,以此类推,可能会造成无限循环。
它可能需要稍后再执行
SwingUtilities.invokeLater(() -> {
comboBox.setModel(comb);
comboBox.setPopupVisible(false);
});
@Override
public void insertUpdate(DocumentEvent e) {
String src = editor.getText();
String[] lista;
System.out.println("el contenido es:"+src);
lista = FiltrarUsuarios(src);
comb = new DefaultComboBoxModel<String>(lista); //usuarios
SwingUtilities.invokeLater(() -> {
comboBox.setModel(comb);
comboBox.setPopupVisible(false);
});
}
@Override
public void removeUpdate(DocumentEvent e) {
String src = editor.getText();
String[] lista;
System.out.println("Ahora es borrar contenido. El contenido es:"+src);
if (src.equals("")) {
comb = new DefaultComboBoxModel<String>(usuarios);
SwingUtilities.invokeLater(() -> {
comboBox.setModel(comb);
comboBox.setPopupVisible(false);
});
} else {
lista = FiltrarUsuarios(src);
comb = new DefaultComboBoxModel<String>(lista); //usuarios
SwingUtilities.invokeLater(() -> {
comboBox.setModel(comb);
comboBox.setPopupVisible(false);
});
}
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。