【问题标题】:How to extend the JComboBox class?如何扩展 JComboBox 类?
【发布时间】:2016-07-15 14:19:07
【问题描述】:

我正在编写一个 Java GUI。我有一些预设 JComboBoxes 并且能够将它们彼此区分开来,我想扩展该类并添加一个 enum 变量来帮助我将它们区分开来。

这是两个标准 JComboBoxes 的 MCVE:

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class XComboBoxMCVE extends JPanel {

    private JComboBox tfComboBox;
    private JComboBox ynComboBox;
    private JComponent[] components;

    public XComboBoxMCVE() {
        setLayout(new BorderLayout());
    
        JPanel comboPanel = new JPanel(new GridLayout(0, 1, 5, 5));

        Boolean[] trueFalse = { true, false };
        DefaultComboBoxModel tfModel = new DefaultComboBoxModel(trueFalse);
        tfComboBox = new JComboBox(tfModel);

        String[] yesNo = { "Yes", "No" };
        DefaultComboBoxModel ynModel = new DefaultComboBoxModel(yesNo);
        ynComboBox = new JComboBox(ynModel);

        components = new JComponent[] { tfComboBox, ynComboBox };
    
        JButton printSelection = new JButton("Print Type");
        printSelection.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                for (JComponent component : components) {
                    // I also have other components in component in program,
                    // therefore this usage..
                    if (component instanceof JComboBox) {
                        JComboBox temp = (JComboBox) component;
                        System.out.println("Printing selection: " + temp.getSelectedItem().toString());
                        // if (temp.getBoxType() == BoxType.Company){
                        // System.out.println("Companies say: " +
                        // temp.getSelectedItem().toString());
                        // } else if(temp.getBoxType() == BoxType.Device){
                        // System.out.println("Devices are: " +
                        // temp.getSelectedItem().toString());
                        // }
                    }
                }
            }
        });

        JPanel buttonPane = new JPanel(new GridLayout(0, 1, 5, 5));
        buttonPane.add(printSelection);

        comboPanel.add(tfComboBox);
        comboPanel.add(ynComboBox);

        add(comboPanel, BorderLayout.CENTER);
        add(buttonPane, BorderLayout.PAGE_END);
    }

    public static void createAndShowGUI(){
        JFrame frame = new JFrame("MCVE");
        frame.setLayout(new BorderLayout());
    
        XComboBoxMCVE pane = new XComboBoxMCVE();
        
        frame.add(pane, BorderLayout.CENTER);
        frame.setResizable(false);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                createAndShowGUI();
            }
        });
    }
}

class XComboBox extends JComboBox {
    BoxType type;

    public XComboBox(BoxType type) {
        this.type = type;
    }

    public void setBoxType(BoxType type) {
        this.type = type;
    }

    public BoxType getBoxType() {
        return this.type;
    }

    public enum BoxType {
        Model, Company, Device
    }
}

如上例所示,当用户单击按钮时,我无法区分两个 JComboBoxesBoxType 的一个使用示例是一个BoxType 将打印一种类型的消息,而另一个BoxType 将打印另一种消息。例如:

if(temp.getBoxType() == BoxType.Device){
    System.out.println("The devices are: " + temp.getSelectedItem().toString());
} else if(temp.getBoxType() == BoxType.Company){
    System.out.println("The companies say: " + temp.getSelectedItem().toString());
}

但是我偶然发现了一个构造函数的问题,我尝试使用类似于我对JComboBox 所做的操作并输入一个DefaultComboBoxModel,我还没有在XComboBox 类中实现它。

问题

如何修改XComboBox 类,以便在构造元素时给它一个DefaultComboBoxModel

我希望能够做到这一点:

ynComboBox = new XComboBox(tfModel);
ynComboBox.setBoxType(BoxType.Device);

感谢您的帮助和/或指导!

【问题讨论】:

  • 1.你为什么要首先扩展 JComboBox ,因为你似乎没有改变任何先天行为? 2. 我不确定你真正坚持的是什么或 BoxType 代表什么。 3. 考虑创建真正的minimal reproducible example 代码,我们可以实际运行的代码。
  • 哇..是的。对不起..会尽快解决。出于某种原因,它保存了一个旧标题。
  • 看起来好多了。我认为你想要做的是给JComboBox(或XComboBox)一个以DefaultComboBoxModel为参数的构造函数。类似于以下内容:public XComboBox(DefaultComboBoxModel dcbm) { // set the CB's model }
  • 你可以按照@JonnyHenly 的建议去做,或者为什么不简单地使用JComboBox 的setModel(...) 方法呢?您的类从 JComboBox 扩展而来,因此它具有父类的所有公共方法。话虽如此,如果这是我的项目,我什至不会扩展 JComboBox,而是使用 JComboBoxes,也许创建一个工厂方法来创建我想要的组合。
  • 并且您可以使用 HashMap 之类的 Map 将 JComboBox 与 BoxType 相关联。

标签: java swing jcombobox class-extensions


【解决方案1】:

您需要将 JComboBox 与 BoxType 关联,关联两个对象的最佳方法之一是使用 Map,这里是 Map<BoxType, JComboBox>。完成此操作后,您可以使用组合框轻松提取具有哪些选择。同样,我会避免扩展 JCombo。例如,我的 MCVE:

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;

import javax.swing.BorderFactory;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class XComboBoxMCVE extends JPanel {
    private static final long serialVersionUID = 1L;
    private Map<BoxType, JComboBox<String>> comboMap = new EnumMap<>(BoxType.class);

    public XComboBoxMCVE() {
        setLayout(new BorderLayout());
        JPanel comboPanel = new JPanel(new GridLayout(0, 1, 5, 5));

        // just for example
        String[] modelItemsArray = {"Model Item A", "Model Item B", "Model Item C", "Model Item D"};
        BoxItems modelItems = new BoxItems(BoxType.MODEL, modelItemsArray);
        String[] CompanyItemsArray = {"Company Item A", "Company Item B", "Company Item C", "Company Item D"};
        BoxItems companyItems = new BoxItems(BoxType.COMPANY, CompanyItemsArray);
        String[] deviceItemsArray = {"Device Item A", "Device Item B", "Device Item C", "Device Item D"};
        BoxItems deviceItems = new BoxItems(BoxType.DEVICE, deviceItemsArray);

        createAndPlaceComboBox(BoxType.MODEL, modelItems, comboPanel);
        createAndPlaceComboBox(BoxType.COMPANY, companyItems, comboPanel);
        createAndPlaceComboBox(BoxType.DEVICE, deviceItems, comboPanel);

        JButton printSelection = new JButton("Print Type");
        printSelection.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                for (BoxType boxType : BoxType.values()) {
                    // use the Map to get the appropriate JComboBox
                    JComboBox<String> combo = comboMap.get(boxType);
                    String selection = (String) combo.getSelectedItem();
                    if (selection == null) {
                        selection = "NONE";
                    }
                    String text = String.format("Selection for box type %s: %s: ", 
                            boxType.getText(), selection);
                    System.out.println(text);
                }
            }
        });

        JPanel buttonPane = new JPanel(new GridLayout(0, 1, 5, 5));
        buttonPane.add(printSelection);

        add(comboPanel, BorderLayout.CENTER);
        add(buttonPane, BorderLayout.PAGE_END);
    }

    private void createAndPlaceComboBox(BoxType boxType, BoxItems boxItems, JPanel panel) {
        String[] items = boxItems.getItems().toArray(new String[] {});
        DefaultComboBoxModel<String> comboModel = new DefaultComboBoxModel<>(items); // create model
        JComboBox<String> combo = new JComboBox<>(comboModel); // crteate combo
        comboMap.put(boxType, combo);  // put combo into Map

        JPanel wrapPanel = new JPanel(new BorderLayout());  // wrapper panel that has a title border 
        wrapPanel.add(combo);
        wrapPanel.setBorder(BorderFactory.createTitledBorder(boxType.getText() + " Items"));
        panel.add(wrapPanel);
    }

    public static void createAndShowGUI() {
        JFrame frame = new JFrame("MCVE");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        XComboBoxMCVE pane = new XComboBoxMCVE();
        frame.add(pane, BorderLayout.CENTER);
        frame.setResizable(false);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                createAndShowGUI();
            }
        });
    }
}

// A better enum, one not inside of an unnecessary class
enum BoxType {
    MODEL("Model"), COMPANY("Company"), DEVICE("Device");
    private String text;

    private BoxType(String text) {
        this.text = text;
    }

    public String getText() {
        return text;
    }
}

// class to associate BoxType with possible items associated with it
class BoxItems {
    private BoxType boxType;
    private List<String> items = new ArrayList<>();

    public BoxItems(BoxType boxType) {
        this.boxType = boxType;
    }

    public BoxItems(BoxType boxType, String[] itemsArray) {
        this(boxType);
        for (String item : itemsArray) {
            items.add(item);
        }
    }

    public void addItem(String item) {
        items.add(item);
    }

    public BoxType getBoxType() {
        return boxType;
    }

    public List<String> getItems() {
        // unmodifiable so that can't be changed outside of this class
        return Collections.unmodifiableList(items);
    }
}

【讨论】:

    猜你喜欢
    • 2020-06-22
    • 2013-03-30
    • 2016-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多