java - JComboBox getSelectedIndex 不工作两次?

标签 java swing jcombobox itemlistener

所以我制作了一个利用 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 是一个 boolean。

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

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

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

更新:

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

我有三个 public void 方法

首次运行程序时,扩展 JFrame 的公共(public)“类名”方法会初始化第一个 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);
}
}

最佳答案

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 与正在监听的 JComboBox 不同。为什么?很难说您到目前为止发布的信息,但您可能会创建一个新的 JComboBox,这会以某种方式导致引用解除关联。

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

只是一个通用的解决方案,例如我上面发布的。如需更详细的解决方案,您需要创建并发布您的 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 不是经过测试的 JComboBox。我建议简化您的代码结构,并坚持下去......

<小时/>

编辑2
下面是 MCVE 的一种更加 OOP 的实现,它使用 CardLayout。它仍然可以通过使其更加 MVC 风格来改进,将 View 与控制与模型分离:

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

}

关于java - JComboBox getSelectedIndex 不工作两次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32668254/

相关文章:

java - jcombobox - 检查模型内容是否更改

JavaFx 希腊字符编码

java - 如何使用 split function() 拆分此字符串

java - "Thread-19"java.lang.IllegalStateException : Not on FX application thread; currentThread = Thread-19

java - JTextPane 每次我插入字符串时都会添加大空格

java - JSmooth 生成的 exe 不显示闪屏

java - 翻转 jcombobox 怎么样?

java - 无法让我的组合框和按钮工作。实现带有按钮的框时出现问题

java - 使用 Selenium Webdrivers 方法 "browser.helperApps.neverAsk.saveToDisk"如何在单击链接时自动下载文件

java - JCombobox 箭头消失