5

我有一个包含多个组合框的程序,每个组合框都有自己的动作侦听器。从任何组合框中选择一个项目将更改一个或多个其他组合框中的项目。我遇到的问题是,为一个组合框调用 setSelectedItem() 会触发另一个组合框的动作侦听器,而后者又会触发其他组合框的动作侦听器,等等。

有没有办法避免这种情况,要么只允许从用户输入触发动作侦听器,要么检测到动作不是从用户输入触发的?说不使用 setSelectedItem() 不是一个选项,因为我希望程序能够为每个组合框设置当前选定的项目。提前感谢您的帮助。

4

3 回答 3

1

我不认为这是可能的。如果您在组合框上设置了 actionlistener,那么actionPerformed()每当组合框上生成任何事件时都会调用。它不检查事件是由用户生成还是通过程序生成。

但是你可以在你的组合框上设置mouselistner,所以只有当你点击你的组合框时,才会采取指定的动作。

另一种方法是为此设置标志以检查事件是由用户生成还是通过程序生成。

但我更喜欢在组合框上设置 mouselistener 的第一种技术。

于 2012-05-02T04:43:56.010 回答
0

例如

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;

public class ComboBoxTwo extends JFrame implements ActionListener, ItemListener {

    private static final long serialVersionUID = 1L;
    private JComboBox mainComboBox;
    private JComboBox subComboBox;
    private Hashtable<Object, Object> subItems = new Hashtable<Object, Object>();

    public ComboBoxTwo() {
        String[] items = {"Select Item", "Color", "Shape", "Fruit"};
        mainComboBox = new JComboBox(items);
        mainComboBox.addActionListener(this);
        mainComboBox.addItemListener(this);
        //prevent action events from being fired when the up/down arrow keys are used
        //mainComboBox.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);
        getContentPane().add(mainComboBox, BorderLayout.WEST);
        subComboBox = new JComboBox();//  Create sub combo box with multiple models
        subComboBox.setPrototypeDisplayValue("XXXXXXXXXX"); // JDK1.4
        subComboBox.addItemListener(this);
        getContentPane().add(subComboBox, BorderLayout.EAST);
        String[] subItems1 = {"Select Color", "Red", "Blue", "Green"};
        subItems.put(items[1], subItems1);
        String[] subItems2 = {"Select Shape", "Circle", "Square", "Triangle"};
        subItems.put(items[2], subItems2);
        String[] subItems3 = {"Select Fruit", "Apple", "Orange", "Banana"};
        subItems.put(items[3], subItems3);
//      mainComboBox.setSelectedIndex(1);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        String item = (String) mainComboBox.getSelectedItem();
        Object o = subItems.get(item);
        if (o == null) {
            subComboBox.setModel(new DefaultComboBoxModel());
        } else {
            subComboBox.setModel(new DefaultComboBoxModel((String[]) o));
        }
    }

    @Override
    public void itemStateChanged(ItemEvent e) {
        if (e.getStateChange() == ItemEvent.SELECTED) {
            if (e.getSource() == mainComboBox) {
                if (mainComboBox.getSelectedIndex() != 0) {
                    FirstDialog firstDialog = new FirstDialog(ComboBoxTwo.this,
                            mainComboBox.getSelectedItem().toString(), "Please wait,  Searching for ..... ");
                }
            } 
        }
    }

    private class FirstDialog extends JDialog {

        private static final long serialVersionUID = 1L;

        FirstDialog(final Frame parent, String winTitle, String msgString) {
            super(parent, winTitle);
            setModalityType(Dialog.ModalityType.APPLICATION_MODAL);
            JLabel myLabel = new JLabel(msgString);
            JButton bNext = new JButton("Stop Processes");
            add(myLabel, BorderLayout.CENTER);
            add(bNext, BorderLayout.SOUTH);
            bNext.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent evt) {
                    setVisible(false);
                }
            });
            javax.swing.Timer t = new javax.swing.Timer(1000, new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {
                    setVisible(false);
                }
            });
            t.setRepeats(false);
            t.start();
            setLocationRelativeTo(parent);
            setSize(new Dimension(400, 100));
            setVisible(true);
        }
    }

    public static void main(String[] args) {
        JFrame frame = new ComboBoxTwo();
        frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}
于 2012-05-02T13:47:18.663 回答
0

一种选择是添加 PopupMenuListener 而不是动作侦听器。它的popupMenuWillBecomeInvisible方法将在用户手动选择一个项目后触发,但不会在调用setSelectedItemsetSelectedIndex或之后触发。addItem

我发现此方法有一个限制:如果用户保持下拉菜单关闭并通过键入第一个字母来选择项目,则弹出侦听器不会触发。在下面的示例中,我通过阻止用户通过键入字母字符来选择项目来解决此问题。

import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;

public class ComboBoxExample extends JFrame {

    public static void main(String[] args) {

        JFrame frame = new JFrame("JComboBox Example");

        // Create combo box
        JComboBox homeTypeComboBox = new JComboBox(new String[]{"House", "Condo", "Apartment"});
        
        // add the popup listener
        homeTypeComboBox.addPopupMenuListener(new HomeTypeChangeListener());

        // prevent user from selecting an item by typing its first letter
        homeTypeComboBox.setKeySelectionManager((key, model) -> { return -1; });

        JPanel panel = new JPanel();
        panel.add(homeTypeComboBox);

        frame.add(panel);
        frame.setSize(300, 150);
        frame.show();

        // These will not generate print statements
        homeTypeComboBox.setSelectedItem("House");
        homeTypeComboBox.setSelectedItem("Condo");
        homeTypeComboBox.setSelectedItem("Apartment");
    }

    private static class HomeTypeChangeListener implements PopupMenuListener {
        
        public void popupMenuWillBecomeVisible(PopupMenuEvent e) {}

        public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
            // triggered when user makes a dropdown selection
            System.out.println("User changed the dropdown selection. This will not be triggered for programmatic" 
                + " calls to JComboBox::setSelectedItem, JComboBox::setSelectedIndex, or JComboBox::addItem.");
        }

        public void popupMenuCanceled(PopupMenuEvent e) {}
    }

}

于 2022-02-20T05:48:29.610 回答