import java.awt.BorderLayout; import java.awt.Container; import java.awt.Font; import java.awt.Frame; import java.awt.GraphicsEnvironment; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.ArrayList; import java.util.Iterator; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.border.EtchedBorder; import javax.swing.border.TitledBorder; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; /** * This is a JDialog subclass that allows the user to select a font, in any * style and size, from the list of available fonts on the system. The dialog is * modal. Display it with show(); this method does not return until the user * dismisses the dialog. When show() returns, call getSelectedFont() to obtain * the user's selection. If the user clicked the dialog's "Cancel" button, * getSelectedFont() will return null. */ public class FontChooser extends JDialog { // These fields define the component properties String family; // The name of the font family int style; // The font style int size; // The font size Font selectedFont; // The Font they correspond to // This is the list of all font families on the system String[] fontFamilies; // The various Swing components used in the dialog ItemChooser families, styles, sizes; JTextArea preview; JButton okay, cancel; // The names to appear in the "Style" menu static final String[] styleNames = new String[] { "Plain", "Italic", "Bold", "BoldItalic" }; // The style values that correspond to those names static final Integer[] styleValues = new Integer[] { new Integer(Font.PLAIN), new Integer(Font.ITALIC), new Integer(Font.BOLD), new Integer(Font.BOLD + Font.ITALIC) }; // The size "names" to appear in the size menu static final String[] sizeNames = new String[] { "8", "10", "12", "14", "18", "20", "24", "28", "32", "40", "48", "56", "64", "72" }; // This is the default preview string displayed in the dialog box static final String defaultPreviewString = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\n" + "abcdefghijklmnopqrstuvwxyz\n" + "1234567890!@#$%^&*()_-=+[]{}<,.>\n" + "The quick brown fox jumps over the lazy dog"; /** Create a font chooser dialog for the specified frame. */ public FontChooser(Frame owner) { super(owner, "Choose a Font"); // Set dialog frame and title // This dialog must be used as a modal dialog. In order to be used // as a modeless dialog, it would have to fire a PropertyChangeEvent // whenever the selected font changed, so that applications could be // notified of the user's selections. setModal(true); // Figure out what fonts are available on the system GraphicsEnvironment env = GraphicsEnvironment .getLocalGraphicsEnvironment(); fontFamilies = env.getAvailableFontFamilyNames(); // Set initial values for the properties family = fontFamilies[0]; style = Font.PLAIN; size = 18; selectedFont = new Font(family, style, size); // Create ItemChooser objects that allow the user to select font // family, style, and size. families = new ItemChooser("Family", fontFamilies, null, 0, ItemChooser.COMBOBOX); styles = new ItemChooser("Style", styleNames, styleValues, 0, ItemChooser.COMBOBOX); sizes = new ItemChooser("Size", sizeNames, null, 4, ItemChooser.COMBOBOX); // Now register event listeners to handle selections families.addItemChooserListener(new ItemChooser.Listener() { public void itemChosen(ItemChooser.Event e) { setFontFamily((String) e.getSelectedValue()); } }); styles.addItemChooserListener(new ItemChooser.Listener() { public void itemChosen(ItemChooser.Event e) { setFontStyle(((Integer) e.getSelectedValue()).intValue()); } }); sizes.addItemChooserListener(new ItemChooser.Listener() { public void itemChosen(ItemChooser.Event e) { setFontSize(Integer.parseInt((String) e.getSelectedValue())); } }); // Create a component to preview the font. preview = new JTextArea(defaultPreviewString, 5, 40); preview.setFont(selectedFont); // Create buttons to dismiss the dialog, and set handlers on them okay = new JButton("Okay"); cancel = new JButton("Cancel"); okay.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { hide(); } }); cancel.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { selectedFont = null; hide(); } }); // Put the ItemChoosers in a Box Box choosersBox = Box.createHorizontalBox(); choosersBox.add(Box.createHorizontalStrut(15)); choosersBox.add(families); choosersBox.add(Box.createHorizontalStrut(15)); choosersBox.add(styles); choosersBox.add(Box.createHorizontalStrut(15)); choosersBox.add(sizes); choosersBox.add(Box.createHorizontalStrut(15)); choosersBox.add(Box.createGlue()); // Put the dismiss buttons in another box Box buttonBox = Box.createHorizontalBox(); buttonBox.add(Box.createGlue()); buttonBox.add(okay); buttonBox.add(Box.createGlue()); buttonBox.add(cancel); buttonBox.add(Box.createGlue()); // Put the choosers at the top, the buttons at the bottom, and // the preview in the middle. Container contentPane = getContentPane(); contentPane.add(new JScrollPane(preview), BorderLayout.CENTER); contentPane.add(choosersBox, BorderLayout.NORTH); contentPane.add(buttonBox, BorderLayout.SOUTH); // Set the dialog size based on the component size. pack(); } /** * Call this method after show() to obtain the user's selection. If the user * used the "Cancel" button, this will return null */ public Font getSelectedFont() { return selectedFont; } // These are other property getter methods public String getFontFamily() { return family; } public int getFontStyle() { return style; } public int getFontSize() { return size; } // The property setter methods are a little more complicated. // Note that none of these setter methods update the corresponding // ItemChooser components as they ought to. public void setFontFamily(String name) { family = name; changeFont(); } public void setFontStyle(int style) { this.style = style; changeFont(); } public void setFontSize(int size) { this.size = size; changeFont(); } public void setSelectedFont(Font font) { selectedFont = font; family = font.getFamily(); style = font.getStyle(); size = font.getSize(); preview.setFont(font); } // This method is called when the family, style, or size changes protected void changeFont() { selectedFont = new Font(family, style, size); preview.setFont(selectedFont); } // Override this inherited method to prevent anyone from making us modeless public boolean isModal() { return true; } public static void main(String[] args) { // Create some components and a FontChooser dialog final JFrame frame = new JFrame("demo"); final JButton button = new JButton("Push Me!"); final FontChooser chooser = new FontChooser(frame); // Handle button clicks button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { // Pop up the dialog chooser.show(); // Get the user's selection Font font = chooser.getSelectedFont(); // If not cancelled, set the button font if (font != null) button.setFont(font); } }); // Display the demo frame.getContentPane().add(button); frame.setSize(200, 100); frame.show(); } } /** * This class is a Swing component that presents a choice to the user. It allows * the choice to be presented in a JList, in a JComboBox, or with a bordered * group of JRadioButton components. Additionally, it displays the name of the * choice with a JLabel. It allows an arbitrary value to be associated with each * possible choice. Note that this component only allows one item to be selected * at a time. Multiple selections are not supported. */ class ItemChooser extends JPanel { // These fields hold property values for this component String name; // The overall name of the choice String[] labels; // The text for each choice option Object[] values; // Arbitrary values associated with each option int selection; // The selected choice int presentation; // How the choice is presented // These are the legal values for the presentation field public static final int LIST = 1; public static final int COMBOBOX = 2; public static final int RADIOBUTTONS = 3; // These components are used for each of the 3 possible presentations JList list; // One type of presentation JComboBox combobox; // Another type of presentation JRadioButton[] radiobuttons; // Yet another type // The list of objects that are interested in our state ArrayList listeners = new ArrayList(); // The constructor method sets everything up public ItemChooser(String name, String[] labels, Object[] values, int defaultSelection, int presentation) { // Copy the constructor arguments to instance fields this.name = name; this.labels = labels; this.values = values; this.selection = defaultSelection; this.presentation = presentation; // If no values were supplied, use the labels if (values == null) this.values = labels; // Now create content and event handlers based on presentation type switch (presentation) { case LIST: initList(); break; case COMBOBOX: initComboBox(); break; case RADIOBUTTONS: initRadioButtons(); break; } } // Initialization for JList presentation void initList() { list = new JList(labels); // Create the list list.setSelectedIndex(selection); // Set initial state // Handle state changes list.addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { ItemChooser.this.select(list.getSelectedIndex()); } }); // Lay out list and name label vertically this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); // vertical this.add(new JLabel(name)); // Display choice name this.add(new JScrollPane(list)); // Add the JList } // Initialization for JComboBox presentation void initComboBox() { combobox = new JComboBox(labels); // Create the combo box combobox.setSelectedIndex(selection); // Set initial state // Handle changes to the state combobox.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { ItemChooser.this.select(combobox.getSelectedIndex()); } }); // Lay out combo box and name label horizontally this.setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); this.add(new JLabel(name)); this.add(combobox); } // Initialization for JRadioButton presentation void initRadioButtons() { // Create an array of mutually exclusive radio buttons radiobuttons = new JRadioButton[labels.length]; // the array ButtonGroup radioButtonGroup = new ButtonGroup(); // used for exclusion ChangeListener listener = new ChangeListener() { // A shared listener public void stateChanged(ChangeEvent e) { JRadioButton b = (JRadioButton) e.getSource(); if (b.isSelected()) { // If we received this event because a button was // selected, then loop through the list of buttons to // figure out the index of the selected one. for (int i = 0; i < radiobuttons.length; i++) { if (radiobuttons[i] == b) { ItemChooser.this.select(i); return; } } } } }; // Display the choice name in a border around the buttons this.setBorder(new TitledBorder(new EtchedBorder(), name)); this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); // Create the buttons, add them to the button group, and specify // the event listener for each one. for (int i = 0; i < labels.length; i++) { radiobuttons[i] = new JRadioButton(labels[i]); if (i == selection) radiobuttons[i].setSelected(true); radiobuttons[i].addChangeListener(listener); radioButtonGroup.add(radiobuttons[i]); this.add(radiobuttons[i]); } } // These simple property accessor methods just return field values // These are read-only properties. The values are set by the constructor // and may not be changed. public String getName() { return name; } public int getPresentation() { return presentation; } public String[] getLabels() { return labels; } public Object[] getValues() { return values; } /** Return the index of the selected item */ public int getSelectedIndex() { return selection; } /** Return the object associated with the selected item */ public Object getSelectedValue() { return values[selection]; } /** * Set the selected item by specifying its index. Calling this method * changes the on-screen display but does not generate events. */ public void setSelectedIndex(int selection) { switch (presentation) { case LIST: list.setSelectedIndex(selection); break; case COMBOBOX: combobox.setSelectedIndex(selection); break; case RADIOBUTTONS: radiobuttons[selection].setSelected(true); break; } this.selection = selection; } /** * This internal method is called when the selection changes. It stores the * new selected index, and fires events to any registered listeners. The * event listeners registered on the JList, JComboBox, or JRadioButtons all * call this method. */ protected void select(int selection) { this.selection = selection; // Store the new selected index if (!listeners.isEmpty()) { // If there are any listeners registered // Create an event object to describe the selection ItemChooser.Event e = new ItemChooser.Event(this, selection, values[selection]); // Loop through the listeners using an Iterator for (Iterator i = listeners.iterator(); i.hasNext();) { ItemChooser.Listener l = (ItemChooser.Listener) i.next(); l.itemChosen(e); // Notify each listener of the selection } } } // These methods are for event listener registration and deregistration public void addItemChooserListener(ItemChooser.Listener l) { listeners.add(l); } public void removeItemChooserListener(ItemChooser.Listener l) { listeners.remove(l); } /** * This inner class defines the event type generated by ItemChooser objects * The inner class name is Event, so the full name is ItemChooser.Event */ public static class Event extends java.util.EventObject { int selectedIndex; // index of the selected item Object selectedValue; // the value associated with it public Event(ItemChooser source, int selectedIndex, Object selectedValue) { super(source); this.selectedIndex = selectedIndex; this.selectedValue = selectedValue; } public ItemChooser getItemChooser() { return (ItemChooser) getSource(); } public int getSelectedIndex() { return selectedIndex; } public Object getSelectedValue() { return selectedValue; } } /** * This inner interface must be implemented by any object that wants to be * notified when the current selection in a ItemChooser component changes. */ public interface Listener extends java.util.EventListener { public void itemChosen(ItemChooser.Event e); } /** * This inner class is a simple demonstration of the ItemChooser component * It uses command-line arguments as ItemChooser labels and values. */ public static class Demo { public static void main(String[] args) { // Create a window, arrange to handle close requests final JFrame frame = new JFrame("ItemChooser Demo"); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); // A "message line" to display results in final JLabel msgline = new JLabel(" "); // Create a panel holding three ItemChooser components JPanel chooserPanel = new JPanel(); final ItemChooser c1 = new ItemChooser("Choice #1", args, null, 0, ItemChooser.LIST); final ItemChooser c2 = new ItemChooser("Choice #2", args, null, 0, ItemChooser.COMBOBOX); final ItemChooser c3 = new ItemChooser("Choice #3", args, null, 0, ItemChooser.RADIOBUTTONS); // An event listener that displays changes on the message line ItemChooser.Listener l = new ItemChooser.Listener() { public void itemChosen(ItemChooser.Event e) { msgline.setText(e.getItemChooser().getName() + ": " + e.getSelectedIndex() + ": " + e.getSelectedValue()); } }; c1.addItemChooserListener(l); c2.addItemChooserListener(l); c3.addItemChooserListener(l); // Instead of tracking every change with a ItemChooser.Listener, // applications can also just query the current state when // they need it. Here's a button that does that. JButton report = new JButton("Report"); report.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { // Note the use of multi-line italic HTML text // with the JOptionPane message dialog box. String msg = "" + c1.getName() + ": " + c1.getSelectedValue() + "
" + c2.getName() + ": " + c2.getSelectedValue() + "
" + c3.getName() + ": " + c3.getSelectedValue() + "
"; JOptionPane.showMessageDialog(frame, msg); } }); // Add the 3 ItemChooser objects, and the Button to the panel chooserPanel.add(c1); chooserPanel.add(c2); chooserPanel.add(c3); chooserPanel.add(report); // Add the panel and the message line to the window Container contentPane = frame.getContentPane(); contentPane.add(chooserPanel, BorderLayout.CENTER); contentPane.add(msgline, BorderLayout.SOUTH); // Set the window size and pop it up. frame.pack(); frame.show(); } } }