【问题标题】:JComboBox getSelectedIndex not working twice?JComboBox getSelectedIndex 不工作两次?
【发布时间】:2015-09-19 12:32:12
【问题描述】:

所以我制作了一个利用 JComboBox 的程序。我添加了一个项目监听器,如下所示:

wellbox.addItemListener(
            new ItemListener(){
                @Override
                public void itemStateChanged(ItemEvent ie) {
                    if (ie.getStateChange() == ItemEvent.SELECTED){
                        well = (wellbox.getSelectedIndex()-1);
                        if (well >=0){selected = true;}
                    }
                }
            }
    );

wellbox 是 JComboBox 变量 well 是一个 int 并且 selected 是一个布尔值。

现在,项目监听器在第一次执行时工作,没问题。但是,在程序结束时,我有一个选项可以提示用户查看是否要再次运行该程序。整个代码本质上包裹在一个 while(true) 循环中,如果用户说不,他们不想再次运行,该循环就会中断。如果再次运行第二次,项目侦听器将停止工作,并且 getSelectedIndex() 不再返回所选索引。有人知道为什么吗?

再次运行时,JCombo Box 会再次初始化

我希望我已经提供了足够的信息来获得解决方案。

更新:

通过建议给予我会尝试更好地提出我的问题

我有三个公共的 void 方法

在第一次运行程序时,扩展 JFrame 的公共“类名”方法初始化第一个 part1 方法,该方法构建第一个 JPanel 并将其添加到 JFrame。单击按钮后,第一个 JPanel 将从 JFrame 中删除,第一个方法将我们带到第二个方法

在第二种方法中,第二个 JPanel 被构建,并添加到 JFrame。单击另一个按钮后,第二个 JPanel 将从 JFrame 中删除,第二个方法将我们带到第三个方法

第三种方法构建第三个 JPanel 并将其添加到 JFrame。然后,一旦单击按钮,所有内容都会使用以下代码删除:

                    part1.removeAll();
                    part2.removeAll();
                    part3.removeAll();

第三个方法然后从 JFrame 中删除第三个 JPanel。如果用户单击表示他们希望再次运行它的按钮,则第三种方法再次将我们带到第一种方法,再次重建 JPanel 并添加它们...

在第二种方法中,在第二个 JPanel 中,我有一个 JComboBox 正在初始化并添加到第二个 JPanel。第一次,它按原样运行,项目侦听器返回正确的索引。但是一旦如前所述再次运行,在删除所有内容然后重新构建之后,项目侦听器不再返回索引值。有谁知道为什么?

如果需要,这几乎是我的代码。我没有描述我正在使用的任何方法都是不重要的。我已经取出了一堆与这个问题完全无关的代码。

主类:

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

public class ReportCardGenerator {


public static void main(String[] args) {
    debugReportGUI f = new debugReportGUI();
    f.setVisible(true);
}

}

debugReportGUI 类

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

public class debugReportGUI extends JFrame
{
JPanel part1 = new JPanel ();
JPanel part2 = new JPanel ();
JPanel part3 = new JPanel ();
JComboBox wellbox;
JButton cont = new JButton ("Continue");
int buttonW = 110, buttonL = 30, well = -1;
Actions AL = new Actions ();
String[] skills = {"", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",   "10"};

public debugReportGUI ()
{
    super ("JFrame");
    setLayout (new BorderLayout ());
    setSize (800, 700);
    setLocationRelativeTo (null);
    setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
    setResizable (false);

    add (part1, BorderLayout.CENTER);
    Part1 ();
}


public void Part1 ()
{
    part1.setLayout (null);
    part1.add (cont);
    cont.addActionListener (AL);
    cont.setBounds (325, 630, buttonW, buttonL);
    cont.setToolTipText ("Once all fields have been completed press to   continue to next part of Generator");
}


private class Actions implements ActionListener
{
    public void actionPerformed (ActionEvent ae)
    {
        if (ae.getSource () == cont)
        {
            part1.setVisible(false);
            add (part2, BorderLayout.CENTER);
            part2.setVisible (true);
            Part2 ();
        }
    }
}


public void Part2 ()
{
    part2.setLayout (null);
    wellbox = new JComboBox (skills);
    part2.add (wellbox);
    wellbox.setLocation (75, 120);
    wellbox.setSize (650, 40);
    wellbox.addItemListener (
            new ItemListener ()
            {
                //@ Override
                public void itemStateChanged (ItemEvent ie)
                {
                    if (ie.getStateChange () == ItemEvent.SELECTED)
                    {
                        well = (wellbox.getSelectedIndex () - 1);
                        System.out.println (well);
                        /*Initialized value of well is -1*/
                    }
                }
            }
    );
    JButton cont2 = new JButton ("Continue");
    cont2.setBounds (345, 625, buttonW, buttonL);
    cont2.setToolTipText ("When the skill for the ''well done'' comment and    all failed items have been selected, press button ");
    cont2.addActionListener (
            new ActionListener ()
            {
                //@ Override
                public void actionPerformed (ActionEvent ae)
                {
                    if (well >= 0)
                    {
                        part2.setVisible(false);
                        add (part3, BorderLayout.CENTER);
                        part3.setVisible (true);
                        Part3 ();
                    }
                    else{
                    JOptionPane.showMessageDialog(null,"must select an       option in the JComboBox","",JOptionPane.ERROR_MESSAGE);
                    }
                }
            }
    );
    part2.add (cont2);
}


public void Part3 ()
{
    part3.setLayout (null);
    JButton again = new JButton ("Write Another");
    again.setBounds (530, 550, buttonW + 30, buttonL);
    again.setToolTipText ("If you are finished with  report card you can                   write another one for another student by clicking this button");
    again.addActionListener (
            new ActionListener ()
            {
                //@ Override
                public void actionPerformed (ActionEvent ae)
                {
well = -1;
                    part1.removeAll ();
                    part2.removeAll ();
                    part3.removeAll ();
                    remove (part3);
                    add (part1, BorderLayout.CENTER);
                    part1.setVisible (true);
                    Part1 ();
                }
            }
    );
    part3.add(again);
}
}

【问题讨论】:

    标签: java swing jcombobox itemlistener


    【解决方案1】:

    整个代码本质上包裹在一个 while(true) 循环中,如果用户说不,他们不想再次运行,该循环就会中断。

    虽然这对于简单的线性控制台(纯文本)程序来说很好,但这种结构不适用于事件驱动程序。相反,您应该将 GUI 的组件重新设置为其原始状态(如何执行此操作的详细信息将取决于程序的结构和组件,我们尚不知道)并摆脱 while (true) 块.

    如果再次运行第二次,项目侦听器将停止工作,getSelectedIndex() 不再返回所选索引。

    我的猜测是您的参考文献不正确。当您重新运行代码时,显示的 JComboBox 与正在收听的 JComboBox 不同。为什么?很难用您迄今为止发布的信息说,但您可能正在创建一个新的 JComboBox,这会以某种方式导致引用解除关联。

    我希望我已经提供了足够的信息来获得解决方案。

    只是我在上面发布的一般解决方案。如需更详细的解决方案,您需要创建并发布您的 Minimal, Complete, and Verifiable example


    编辑:一个小的可运行程序,它使用上面发布的代码,但不会重现您遇到的问题。请注意,您的代码和我对您的代码的推导存在不相关的问题,我尚未修复:

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    
    @SuppressWarnings("serial")
    public class ReportGUI extends JFrame {
        JPanel part1 = new JPanel();
        JPanel part2 = new JPanel();
        JPanel part3 = new JPanel();
    
        // !! added
        private JComboBox<String> wellbox;
        protected int well;
        protected boolean selected;
        private String[] DUMMY_DATA = { "Monday", "Tuesday", "Wednesday",
                "Thursday", "Friday" };
    
        public ReportGUI() {
            super("Report Card Generator");
            setLayout(new BorderLayout());
            setSize(800, 700);
            setLocationRelativeTo(null);
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setResizable(false);
    
            // v.lvl = 10; add(part2, BorderLayout.CENTER); Part2();
    
            add(part1, BorderLayout.CENTER);
            Part1();
        }
    
        public void Part1() {
            JButton nextPartBtn = new JButton("Next Part");
            nextPartBtn.addActionListener(new Actions());
            part1.add(nextPartBtn);
        }
    
        private class Actions implements ActionListener {
            public void actionPerformed(ActionEvent ae) {
                remove(part1);
                add(part2, BorderLayout.CENTER);
                part2.setVisible(true);
                Part2();
    
                //!!
                revalidate();
                repaint();
            }
        }
    
        public void Part2() {
            /* building JPanel part2 */
            // !! wellbox = new JComboBox(v.wellskills[v.lvl]);
            wellbox = new JComboBox<>(DUMMY_DATA);
            part2.add(wellbox);
            wellbox.setLocation(75, 120);
            wellbox.setSize(650, 40);
            wellbox.addItemListener(new ItemListener() {
                @Override
                public void itemStateChanged(ItemEvent ie) {
                    if (ie.getStateChange() == ItemEvent.SELECTED) {
                        well = (wellbox.getSelectedIndex() - 1);
                        System.out.println(well);
                        if (well >= 0) {
                            selected = true;
                        }
                    }
                }
            });
            /* rest of building JPanel part2 */
    
            //!!
            JButton showPart3Btn = new JButton(new AbstractAction("Show Part 3") {
    
                @Override
                public void actionPerformed(ActionEvent arg0) {
                    remove(part2);
                    add(part3, BorderLayout.CENTER);
                    part3.setVisible(true);
                    Part3();
                    revalidate();
                    repaint();
                }
            });
    
            part2.add(showPart3Btn);
    
        }
    
        public void Part3() {
            /* building JPanel part3 */
            part1.removeAll();
            part2.removeAll();
            part3.removeAll();
            remove(part3);
            add(part1, BorderLayout.CENTER);
            // part1.setVisible(true);
            Part1();
            revalidate();
            repaint();
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    new ReportGUI().setVisible(true);
                }
            });
        }
    }
    

    编辑

    使用您的最新代码,添加一些调试行,包括:

    private class Actions implements ActionListener {
        public void actionPerformed(ActionEvent ae) {
            if (ae.getSource() == cont) {
                ActionListener[] listeners = ((AbstractButton) cont).getActionListeners();
                System.out.println("number of listeners added to cont: " + listeners.length);
    
                part1.setVisible(false);
                add(part2, BorderLayout.CENTER);
                part2.setVisible(true);
                Part2();
            }
        }
    }
    

    public void Part2() {
        part2.setLayout(null);
        wellbox = new JComboBox(skills);
        System.out.println("wellbox created. hashcode: " + wellbox.hashCode());
        part2.add(wellbox);
        wellbox.setLocation(75, 120);
        wellbox.setSize(650, 40);
        wellbox.addItemListener(new ItemListener() {
            // @ Override
            public void itemStateChanged(ItemEvent ie) {
                if (ie.getStateChange() == ItemEvent.SELECTED) {
                    System.out.println("wellbox state change. hashcode: " + wellbox.hashCode());
                    well = (wellbox.getSelectedIndex() - 1);
                    System.out.println(well);
                }
            }
        });
    

    当您运行此程序时,您会看到 cont 按钮没有重新创建,并且添加了多个 ActionListener,因此显示的 JComboBox 不是经过测试的那个。我建议简化你的代码结构,并坚持下去......


    编辑 2
    这是 MCVE 的更多 OOP 实现,它使用 CardLayout。它仍然可以通过使其更加 MVC-ish 来改进,将视图与控制与模型分离:

    import java.awt.BorderLayout;
    import java.awt.CardLayout;
    import java.awt.Component;
    import java.awt.Dimension;
    import java.awt.event.ActionEvent;
    import java.awt.event.ItemListener;
    import javax.swing.*;
    
    @SuppressWarnings("serial")
    public class DebugReport2 extends JPanel {
        private static final int PREF_W = 800;
        private static final int PREF_H = 700;
        public static final String PART_1 = "part 1";
        public static final String PART_2 = "part 2";
        public static final String PART_3 = "part 3";
        private CardLayout cardLayout = new CardLayout();
        private Part1Panel part1Panel = new Part1Panel(this);
        private Part2Panel part2Panel = new Part2Panel(this);
        private Part3Panel part3Panel = new Part3Panel(this);
    
        public DebugReport2() {
            setLayout(cardLayout);
            System.out.println(Part1Panel.class.getName());
            add(part1Panel, PART_1);
            add(part2Panel, PART_2);
            add(part3Panel, PART_3);
        }
    
        // public method to allow other classes to swap views
        public void showCard(String key) {
            cardLayout.show(this, key);
        }
    
        public void part2Reset() {
            part2Panel.reset();
        }
    
        public void setPart3SelectedOptionText(String selectedItem) {
            part3Panel.setSelectedOptionText(selectedItem);
        }
    
        @Override
        public Dimension getPreferredSize() {
            if (isPreferredSizeSet()) {
                return super.getPreferredSize();
            }
            return new Dimension(PREF_W, PREF_H);
        }
    
        private static void createAndShowGui() {
            DebugReport2 mainPanel = new DebugReport2();
    
            JFrame frame = new JFrame("Debug Report 2");
            frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            frame.getContentPane().add(mainPanel);
            frame.pack();
            frame.setLocationByPlatform(true);
            frame.setVisible(true);
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    createAndShowGui();
                }
            });
        }
    }
    
    @SuppressWarnings("serial")
    class BaseContinueAction extends AbstractAction {
        private String key;
        private DebugReport2 debugReport2;
    
        public BaseContinueAction(String name, DebugReport2 debugReport2, String key) {
            super(name);
            int mnemnoic = (int) name.charAt(0);
            putValue(MNEMONIC_KEY, mnemnoic); // first letter is mnemonic alt-key press.
            this.key = key;
            this.debugReport2 = debugReport2;
        }
    
        public String getKey() {
            return key;
        }
    
        public DebugReport2 getDebugReport2() {
            return debugReport2;
        }
    
        @Override
        public void actionPerformed(ActionEvent e) {
            debugReport2.showCard(key);
        }
    }
    
    @SuppressWarnings("serial")
    class Part1Panel extends JPanel {
        private DebugReport2 debugReport2;
    
        public Part1Panel(DebugReport2 debugReport2) {
            this.debugReport2 = debugReport2;
            setBorder(BorderFactory.createTitledBorder("Part 1 Panel")); // for debug purposes
    
            JPanel bottomPanel = new JPanel();
            bottomPanel.add(new JButton(new ContinueAction("Continue", debugReport2, DebugReport2.PART_2)));
    
            setLayout(new BorderLayout());
            add(bottomPanel, BorderLayout.SOUTH);
        }
    
        private class ContinueAction extends BaseContinueAction {
    
            public ContinueAction(String name, DebugReport2 debugReport2, String key) {
                super(name, debugReport2, key);
            }
    
            @Override
            public void actionPerformed(ActionEvent e) {
                super.actionPerformed(e);
                getDebugReport2().part2Reset();
            }
    
        }
    }
    
    @SuppressWarnings("serial")
    class Part2Panel extends JPanel {
        private static final String[] DEFAULT_DATA = {"0", "1", "2", "3", "4", "5", "6"};
    
        private DebugReport2 debugReport2;
        private ComboBoxModel<String> comboModel = new DefaultComboBoxModel<>();
        private JComboBox<String> skillsCombo = new JComboBox<>(comboModel);
    
        public Part2Panel(DebugReport2 debugReport2) {
            ((DefaultComboBoxModel<String>)comboModel).addElement("");
            for (String item : DEFAULT_DATA) {
                ((DefaultComboBoxModel<String>)comboModel).addElement("Selection " + item);
            }
    
            this.debugReport2 = debugReport2;
            setBorder(BorderFactory.createTitledBorder("Part 2 Panel")); // for debug purposes
    
            JPanel centerPanel = new JPanel(); // uses default FlowLayout
            centerPanel.add(skillsCombo);
    
            JPanel bottomPanel = new JPanel(); // again default FlowLayout
            bottomPanel.add(new JButton(new ContinueAction("Continue", debugReport2, DebugReport2.PART_3)));
    
            setLayout(new BorderLayout());
            add(centerPanel, BorderLayout.CENTER);
            add(bottomPanel, BorderLayout.PAGE_END);
    
        }
    
        // if you need outside classes to be able to change the combo box model
        // also resets selected index to -1
        public void setComboModel(ComboBoxModel<String> comboModel) {
    
            // reset combobox selection to -1, but remove listeners before doing so, and then
            // re-add them afterwards
            ItemListener[] itemListeners = skillsCombo.getItemListeners();
            for (ItemListener itemListener : itemListeners) {
                skillsCombo.removeItemListener(itemListener);
            }
    
            this.comboModel = comboModel;
            skillsCombo.setModel(comboModel);
            skillsCombo.setSelectedIndex(-1);
    
            for (ItemListener itemListener : itemListeners) {
                skillsCombo.addItemListener(itemListener);
            }
        }
    
        public void reset() {
            ComboBoxModel<String> model = skillsCombo.getModel();
            setComboModel(model);
        }
    
        private class ContinueAction extends BaseContinueAction {
    
            private String selectedItem = "";
    
            public ContinueAction(String name, DebugReport2 debugReport2, String key) {
                super(name, debugReport2, key);
            }
    
            @Override
            public void actionPerformed(ActionEvent e) {
                selectedItem = (String) skillsCombo.getSelectedItem();
                if (selectedItem == null || selectedItem.trim().isEmpty()) {
                    Component parent = debugReport2;
                    String title = "Option Not Selected";
                    String message = "You must select an option before continuing";
                    int type = JOptionPane.ERROR_MESSAGE;
                    JOptionPane.showMessageDialog(parent, message, title, type);
                } else {
                    // show the next view in the card layout
                    super.actionPerformed(e);
                    getDebugReport2().setPart3SelectedOptionText(selectedItem);
                }
            }
    
        }
    }
    
    @SuppressWarnings("serial")
    class Part3Panel extends JPanel {
        private DebugReport2 debugReport2;
        private JTextField selectedOptionField = new JTextField(10);
    
        public Part3Panel(DebugReport2 debugReport2) {
            this.debugReport2 = debugReport2;
            setBorder(BorderFactory.createTitledBorder("Part 3 Panel")); // for debug purposes
            add(new JLabel("Selected Option:"));
            add(selectedOptionField);
            add(new JButton(new BaseContinueAction("Continue", debugReport2, DebugReport2.PART_1)));
        }
    
        public void setSelectedOptionText(String text) {
            selectedOptionField.setText(text);
        }
    
    }
    

    【讨论】:

    • 感谢您的回复,我认为我的措辞很糟糕。 IT 实际上并没有被包裹在一个 while(true) 循环中,而是效果是这样的。我有 3 个公共 void 方法,其中第一个将它带到第二个,第二个到第三个,如果在第三个中,他们再说一遍,那么第三个会将它带回第一个。
    • @AntonioK:那么你会想改进你的问题,发布足够的相关代码来帮助我们更好地理解你的问题,最好是minimal reproducible example(请阅读链接作为如何创建的详细信息这很重要)。祝你好运。
    • 我已经扩展了我的问题以尝试解释,希望它有助于找到解决方案...
    • @AntonioK:再次,请阅读minimal reproducible example 链接中的全文,以了解我所追求的内容。你要求我们调试一个复杂的系统,我要求你简化它,这样我不仅能看到问题的本质,还能自己编译和运行代码,体验 第一手的问题。是的,这要求您做很多工作,但要求我们能够更好地理解您的问题和代码,从而为您提供帮助。请理解,我们所有人都是志愿者,因此我们非常感谢您为帮助我们所做的努力。
    • 是的,对不起。我已经删除了一堆代码,只是我所描述的内容以及 part2 方法中存在的问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-20
    • 2011-07-28
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    相关资源
    最近更新 更多