JComboBox getSelectedIndex 没有工作两次?

JComboBox getSelectedIndex not working twice?

所以我制作了一个利用 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 顺便说一句

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

更新:

根据建议,我会尽量更好地提出我的问题

我有三个 public void 方法

首先 运行 启动程序时,扩展 JFrame 的 public "class name" 方法初始化第一个 part1 方法,该方法构建第一个 JPanel 并将其添加到 JFrame。单击按钮后,第一个 JPanel 从 JFrame 中删除,第一个方法将我们带到第二个方法

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

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

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

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

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

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

主要class:

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 Class

    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);
}
}

The entire code is essentially wrapped in a while(true) loop that breaks if the user says no, they do not want to run again.

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

If run again for a second time, the item listener stops working and the getSelectedIndex() is no longer returning the selected index.

我的猜测是您的引用不正确。当您重新运行您的代码时,显示的JComboBox 与正在收听的不一样。为什么?很难说到目前为止您 post 编辑的信息,但您可能正在创建一个新的 JComboBox,它以某种方式导致引用解除关联。

I hope I have provided enough information to get a solution.

只是一个通用的解决方案,就像我在上面 post 编辑的那样。要获得更详细的解决方案,您需要创建 post 您的 Minimal, Complete, and Verifiable example.


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

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);
            }
        }
    });

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


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

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);
    }

}