2

I'm writing a Java GUI. I have a few preset JComboBoxes and to be able to distinct them from each other, I want to extend the class and add an enum variable that can help me distinct them from each other.

Here's an MCVE of two standard JComboBoxes:

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

As the example above is illustrating, there's no way for me to distinct the two JComboBoxes from each other when the user clicks the button. An example of the usage of the BoxType would be that one BoxType would print one type of message while the other BoxType would print another message. E.g:

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

However I have stumbled into a problem with the constructor which I try to use similar to what I did with the JComboBox and input a DefaultComboBoxModel, which I haven't implemented yet in the XComboBox class.

Question

How can I modify the XComboBox class so that I can give it a DefaultComboBoxModel when constructing the element?

I want to be able to do this:

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

Thank you for any help and or guidance!

Community
  • 1
  • 1
Zeliax
  • 4,987
  • 10
  • 51
  • 79
  • 2
    1. Why are you extending JComboBox in the first place as you don't appear to be altering any innate behaviors? 2. I'm not sure what you're actually stuck on or what BoxType represents. 3. Consider creating real [mcve] code, code that we can actually run. – Hovercraft Full Of Eels Jul 15 '16 at 14:22
  • Wow.. yeah. Sorry.. Will fix it all asap. For some reason it saved an old title. – Zeliax Jul 15 '16 at 14:25
  • Done.. Feel free to ask if something is not understandable. The MCVE does not use the XComboBox, but I kept them there as they are part of the question. – Zeliax Jul 15 '16 at 14:59
  • 2
    That looks much better. I think what you want to do is give `JComboBox` (or `XComboBox`) a constructor that takes a `DefaultComboBoxModel` as a parameter. Something like the following: `public XComboBox(DefaultComboBoxModel dcbm) { // set the CB's model }` – Jonny Henly Jul 15 '16 at 15:27
  • 1
    You can do as @JonnyHenly recommends, or why not simply use JComboBox's `setModel(...)` method? Your class extends from JComboBox, and so it has all of the parent class's public methods. Having said this, if this were my project, I wouldn't even extend JComboBox but rather I'd **use** JComboBoxes, and perhaps create a factory method to create the combo that I want. – Hovercraft Full Of Eels Jul 15 '16 at 15:50
  • 1
    And you can associate JComboBox with BoxType using a Map such as a HashMap. – Hovercraft Full Of Eels Jul 15 '16 at 16:07

1 Answers1

2

You need to associate a JComboBox with a BoxType, and one of the best ways to associate two objects is to use a Map, here a Map<BoxType, JComboBox>. Once you've done this, you can easily extract with combo box has which selection. Again, I would avoid extending JCombo. For instance, my 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);
    }
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373