import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.border.*; /** * A GUI application that demos several additional * components * * @author Sharon Tuttle * @version 2015-10-28 */ public class ComponentPlay { /** * creates a ComponentPlayFrame * * @param args not used here */ public static void main(String args[]) { EventQueue.invokeLater( new Runnable() { public void run() { ComponentPlayFrame mainFrame = new ComponentPlayFrame(); mainFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); mainFrame.setVisible(true); } }); } } /** * A frame with a menu bar AND a panel with a variety of components */ class ComponentPlayFrame extends JFrame { // data fields private final static int DEFAULT_WIDTH = 950; private final static int DEFAULT_HEIGHT = 310; /** * constructs a ComponentPlayFrame instance */ public ComponentPlayFrame() { this.setTitle("ComponentPlay"); this.setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); // a JMenuBar cannot be placed on a JPanel -- // it CAN be placed on a JFrame, // using its setJMenuBar method JMenuBar menuBar = new JMenuBar(); this.setJMenuBar(menuBar); // add ComponentPlay panel to frame // (note that I am passing the menuBar // as an argument to the panel constructor // so it can set the menu bar up) ComponentPlayPanel panel = new ComponentPlayPanel(menuBar); this.add(panel); } } /** * a JPanel subclass with several component examples */ class ComponentPlayPanel extends JPanel { //----- // data fields //----- // you can select zero or more taco toppings private JPanel toppingsPanel; private JCheckBox[] tacoToppings; private static final String[] TOPPINGS = {"Sour cream", "Cheese", "Cilantro", "Lettuce", "Salsa", "Pico de Gallo", "Guacamole", "Pepperoni", "Onion", "Greek yogurt"}; private JTextField tacoToppingsSummary; // you can select exactly one taco protein, and specify its // heat level private JPanel proteinAndHeatPanel; private JRadioButton[] tacoProteins; private static final String[] PROTEINS = {"Lean beef", "Steak", "Chicken", "Greasy Pork", "Pepperoni", "Tofu", "Nothing"}; // cheesy: maintain current taco protein choice and // current heat choice as separate values, so // easier to update "separately" private String currentProtein; private int currentHeat; private JTextField currentProteinAndHeat; // you can specify HOW hot you'd like your protein, on // a scale of 0 to HEAT_MAX private JScrollBar heatBar; private int HEAT_MAX = 6; // you can select exactly one taco shell private JPanel shellPanel; private JComboBox<String> shellComboBox; private static final String[] SHELLS = {"Hard corn", "Soft flour", "Soft corn", "Pita", "Waffle", "Lettuce", "White corn", "Dorito Red", "Dorito Blue", "Dorito Purple", "Burrito", "Giant", "Super", "Mini"}; private JTextField currentShell; /** * construct a ComponentPlayPanel instance * * @param mBar the menu bar from the containing * frame, ready to be set up in this constructor */ public ComponentPlayPanel(JMenuBar mBar) { // making this a GridLayout -- one row, three columns this.setLayout(new GridLayout(1, 3)); // set up a File menu on the passed menu bar with a few options setUpFileMenu(mBar); // create a panel for selecting 0 or more taco toppings toppingsPanel = setUpToppingsPanel(); this.add(toppingsPanel); // create a panel for selecting exactly one protein, and // how hot that protein should be proteinAndHeatPanel = setUpProteinAndHeatPanel(); this.add(proteinAndHeatPanel); // allow use to select a shell type for their taco shellPanel = setUpShellPanel(); this.add(shellPanel); } /** * set up a File menu with two options * * @param currMenuBar the current menu bar */ private void setUpFileMenu(JMenuBar currMenuBar) { // add a File menu to the given menu bar JMenu fileMenu = new JMenu("File"); currMenuBar.add(fileMenu); // now, add a Wake Up menu action to the File menu JMenuItem wakeUpMenuItem = new JMenuItem("Wake UP"); wakeUpMenuItem.addActionListener(new WakeUpAction()); wakeUpMenuItem.setActionCommand("Wake UP"); fileMenu.add(wakeUpMenuItem); // and, add a convenient way to Quit at the end of the File menu JMenuItem quitMenuItem = new JMenuItem("Quit"); quitMenuItem.addActionListener(new QuitAction()); quitMenuItem.setActionCommand("Quit"); fileMenu.add(quitMenuItem); } /** * an action listener to quit the application */ private class QuitAction implements ActionListener { /** * quit the application * * @param event selection of the Quit menu item */ public void actionPerformed(ActionEvent event) { System.exit(0); } } /** * an action listener to "wake up" the application with * a splash of yellow */ private class WakeUpAction implements ActionListener { /** * "wake up" the application with a splash of yellow * * @param event selection of the Wake UP menu item */ public void actionPerformed(ActionEvent event) { toppingsPanel.setBackground(Color.YELLOW); proteinAndHeatPanel.setBackground(Color.YELLOW); shellPanel.setBackground(Color.YELLOW); } } /** * set up a sub-panel with checkboxes for selecting 0 or more * taco toppings and a textfield for showing which are * currently selected * * @return a JPanel with taco toppings checkboxes and a * results text field */ private JPanel setUpToppingsPanel() { JPanel newToppingsPanel = new JPanel(); newToppingsPanel.setLayout(new BorderLayout()); newToppingsPanel.setBorder(new EtchedBorder()); // create a vertical box with the toppings checkboxes Box tacoToppingsBox = Box.createVerticalBox(); // create a checkbox for each taco topping tacoToppings = new JCheckBox[TOPPINGS.length]; for (int i=0; i < tacoToppings.length; i++) { tacoToppings[i] = new JCheckBox(TOPPINGS[i]); tacoToppings[i].addItemListener(new TacoToppingChoice()); tacoToppingsBox.add(tacoToppings[i]); } newToppingsPanel.add(tacoToppingsBox, BorderLayout.CENTER); // summary of taco toppings should appear here tacoToppingsSummary = new JTextField(40); tacoToppingsSummary.setEditable(false); newToppingsPanel.add(tacoToppingsSummary, BorderLayout.PAGE_END); return newToppingsPanel; } /** * I'd like to re-display (and update) the taco * toppings summary every time the user * checks OR unchecks a taco topping */ private class TacoToppingChoice implements ItemListener { /** * re-populate the taco toppings summary * textfield every time the state of a * taco topping changes * * @param event a taco topping check or uncheck */ public void itemStateChanged(ItemEvent event) { String tacoToppingsResponse = "toppings: "; for (int i=0; i<TOPPINGS.length; i++) { if (tacoToppings[i].isSelected()) { tacoToppingsResponse += tacoToppings[i].getText() + " "; } } tacoToppingsSummary.setText(tacoToppingsResponse); } } /** * create a panel with grouped radio buttons allowing * the user to select exactly one protein, and a scrollbar * to indicate how "hot" to make the protein selected * * @return a panel with grouped radio buttons allowing the * user to select a taco protein preference and a scrollbar * to select the protein's desired heat level */ private JPanel setUpProteinAndHeatPanel() { JPanel newProteinAndHeatPanel = new JPanel(); newProteinAndHeatPanel.setLayout(new BorderLayout()); newProteinAndHeatPanel.setBorder(new EtchedBorder()); // set up a vertical box of taco protein radio buttons Box proteinBox = setUpProteinBox(); // KLUGE alert: and, ah, add glue and a "choose heat" label // to the bottom of the protein box -- so, ah, choose-heat // label will be right before the choose-heat scrollbar in // the PAGE_END of the overall panel...! proteinBox.add(Box.createVerticalGlue()); proteinBox.add(new JLabel("Choose desired heat level: 0=mildest, " + HEAT_MAX + "=hottest")); newProteinAndHeatPanel.add(proteinBox, BorderLayout.CENTER); // let's add a HOW HOT scrollbar-panel to the bottom of // our proteinAndHeatPanel // make it horizontal, initially with the bar to // to right, with a 1-unit-wide bar, // mininum 0, maximum HEAT_MAX+1 (so 1-unit-wide bar's // "left" end can have the desired value HEAT_MAX) heatBar = new JScrollBar(JScrollBar.HORIZONTAL, HEAT_MAX, 1, 0, (HEAT_MAX+1)); heatBar.addAdjustmentListener(new AdjustHeatAction()); newProteinAndHeatPanel.add(heatBar, BorderLayout.PAGE_END); // make a textfield to show the current protein AND the current heat currentProtein = PROTEINS[0]; currentHeat = heatBar.getValue(); currentProteinAndHeat = new JTextField( "protein: " + currentProtein + " with heat level: " + currentHeat, 30); currentProteinAndHeat.setEditable(false); newProteinAndHeatPanel.add(currentProteinAndHeat, BorderLayout.PAGE_START); return newProteinAndHeatPanel; } /** * set up a vertical box of taco protein radio buttons */ private Box setUpProteinBox() { Box newProteinBox = Box.createVerticalBox(); // need to logically collect radio buttons in a ButtonGroup! ButtonGroup proteinGroup = new ButtonGroup(); // create a radio button for each taco protein tacoProteins = new JRadioButton[PROTEINS.length]; for (int i=0; i< PROTEINS.length; i++) { tacoProteins[i] = new JRadioButton(PROTEINS[i]); tacoProteins[i].addActionListener(new ProteinChoiceAction()); // NOTICE we add each radio button to a logical ButtonGroup -- // so it can make sure ONLY ONE taco protein is // selected at any one time proteinGroup.add(tacoProteins[i]); // (we need to set a radio button's action command to be able to grab // it from an ActionEvent) tacoProteins[i].setActionCommand(PROTEINS[i]); newProteinBox.add(tacoProteins[i]); } // set the first protein option as selected to start tacoProteins[0].setSelected(true); return newProteinBox; } /** * an action listener that displays the latest choice * of taco protein */ private class ProteinChoiceAction implements ActionListener { /** * display the current choice of taco protein * * @param event a taco protein radio button click */ public void actionPerformed(ActionEvent event) { // I can get the action command for the selected // radio button (since I set its action // command when I created it) currentProtein = event.getActionCommand(); currentProteinAndHeat.setText("protein: " + currentProtein + " with heat level: " + currentHeat); } } /** * indicate current heat in the protein text field */ private class AdjustHeatAction implements AdjustmentListener { /** * change the protein's displayed desired heat * when the user adjusts the heat bar * * @param event an adjustment of the heat scrollbar */ public void adjustmentValueChanged(AdjustmentEvent event) { currentHeat = heatBar.getValue(); currentProteinAndHeat.setText("protein: " + currentProtein + " with heat level: " + currentHeat); } } /** * set up a panel with a combo box to specify the desired * taco shell type, and show the current selection * * @return a JPanel with a JComboBox of taco shell choices * and a summarizing textfield */ private JPanel setUpShellPanel() { JPanel newShellPanel = new JPanel(); // ONE of JComboBox's constructors conveniently // accepts an array of desired items for that // combo box -- here I want to use an array // of String instances shellComboBox = new JComboBox<String>(SHELLS); // COMMENT this out if you want the default, // which is UNeditable shellComboBox.setEditable(true); // if you want to SAY how many rows show when // this is selected shellComboBox.setMaximumRowCount(SHELLS.length); shellComboBox.addActionListener(new ShellChoiceAction()); newShellPanel.add(shellComboBox); // now add a summarizing textfield of the current shell choice currentShell = new JTextField( "shell: " + SHELLS[0], 20); currentShell.setEditable(false); newShellPanel.add(currentShell); return newShellPanel; } /** * an action listener that displays the latest choice * of taco shell */ private class ShellChoiceAction implements ActionListener { /** * display the current choice of taco shell * * @param event a shell combo box selection */ public void actionPerformed(ActionEvent event) { // I can get the currently-selected item // in a JComboBox with its getSelectedItem // method currentShell.setText("shell: " + shellComboBox.getSelectedItem() ); } } }