More on GUI • We wrap up our examination of Java GUI programming by looking at several other components and their listeners – The components all come from javax.swing • We will look at JCheckBoxes, JRadioButtons, JSliders, JSpinners, JComboBoxes, JLists, JScrollBars, and how to open multiple windows – Most have their own listeners although we do not necessarily have to use these listeners, we could add JButtons to activate an ActionListener which then can obtain information from these components – You can examine other GUI components from the author’s online material (JMenu, JToolBar, JTabbedPane, JSplitPane, JTree, and JTable) JCheckBox and JRadioButton • These classes extend the JToggleButton class which itself (along with JButton) extend AbstractButton • What these two types of buttons have in common is that they will be in one of two states: selected or not selected – check box allows any number of buttons to be selected – radio button requires buttons be placed into a group where no more than 1 button in a group is selected at a time • Both can be created with strings and/or images and have hot keys (mnemonics) associated with them – to respond to a selected button, you can implement either ActionListener or ItemListener to listen for an ItemEvent • or you could add a JButton, say “Activate”, and in actionPerformed obtain the status of every button (whether selected or not) – code on the next few slides provides a demo for a program which allows the user to format Graphics text, which is input from a JTextField and is changed based on radio and check box selections import import import import java.awt.*; java.awt.event.*; javax.swing.*; javax.swing.border.*; public class GUIEventDemo extends JFrame { private JLabel jlblMessage=new JLabel("Hello", JLabel.CENTER); private JCheckBox jchkBold = new JCheckBox("Bold"); private JCheckBox jchkItalic = new JCheckBox("Italic"); private JRadioButton jrbRed = new JRadioButton("Red"); private JRadioButton jrbGreen = new JRadioButton("Green"); private JRadioButton jrbBlue = new JRadioButton("Blue"); private JTextField jtfMessage = new JTextField(10); public static void main(String[] args) { // details omitted} public GUIEventDemo() { jlblMessage.setBorder(new LineBorder(Color.BLACK, 2)); add(jlblMessage, BorderLayout.CENTER); JPanel jpCheckBoxes = new JPanel(); jpCheckBoxes.setLayout(new GridLayout(2, 1)); jpCheckBoxes.add(jchkBold); jpCheckBoxes.add(jchkItalic); add(jpCheckBoxes, BorderLayout.EAST); JPanel jpRadioButtons = new JPanel(); jpRadioButtons.setLayout(new GridLayout(3, 1)); jpRadioButtons.add(jrbRed); jpRadioButtons.add(jrbGreen); jpRadioButtons.add(jrbBlue); add(jpRadioButtons, BorderLayout.WEST); ButtonGroup group = new ButtonGroup(); group.add(jrbRed); group.add(jrbGreen); group.add(jrbBlue); jrbBlue.setSelected(true); jlblMessage.setForeground(Color.blue); JPanel jpTextField = new JPanel(); jpTextField.setLayout(new BorderLayout(5, 0)); jpTextField.add(new JLabel("Enter a new message"), BorderLayout.WEST); jpTextField.add(jtfMessage, BorderLayout.CENTER); jtfMessage.setHorizontalAlignment(JTextField.RIGHT); add(jpTextField, BorderLayout.NORTH); jchkBold.setMnemonic('B'); jchkItalic.setMnemonic('I'); jrbRed.setMnemonic('E'); jrbGreen.setMnemonic('G'); jrbBlue.setMnemonic('U'); jchkBold.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { setNewFont(); } }); jchkItalic.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { setNewFont(); } }); jrbRed.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { jlblMessage.setForeground(Color.red); } }); jrbGreen.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { jlblMessage.setForeground(Color.green); } }); jrbBlue.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { jlblMessage.setForeground(Color.blue); } }); jtfMessage.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { jlblMessage.setText(jtfMessage.getText()); jtfMessage.requestFocusInWindow(); } }); } private void setNewFont() { int fontStyle = Font.PLAIN; fontStyle += (jchkBold.isSelected() ? Font.BOLD : Font.PLAIN); fontStyle += (jchkItalic.isSelected() ? Font.ITALIC : Font.PLAIN); Font font = jlblMessage.getFont(); jlblMessage.setFont( new Font(font.getName(), fontStyle, font.getSize())); } } ItemListener, ItemEvent • The previous example used anonymous action listeners • When you click on (or use a mnemonic hot key) any radio button or check box, an ItemEvent occurs, and then an ActionEvent occurs • We could have also implemented ItemListener instead of ActionListener – For each of our buttons, we could replace the addActionListener message with the following • buttonname.addItemListener(new ItemListener( ) { @override public void itemStateChanged(ItemEvent e) {…} }); – The … code depends on whether the button is a check box (set foreground color) or radio button (call setNewFont( );) • we would leave the JTextField listener as is as pressing the enter key in a text field generates an ActionEvent (also a TextEvent) but not an ItemEvent Implementing ItemListener • Recall GUI2 which provided a GUI with JCheckBoxes and JRadioButtons • We will finish the GUI by making it respond when the buttons are selected • We will use an ItemListener so that for each selection, an ItemEvent will be captured by the method itemStateChanged – We could also implement an ActionListener for a selection or we could add a JButton • The code on the next slide includes only the differences from GUI2 – In order for the GUI to respond, we add a JLabel to output what has been selected – Since we can select multiple JCheckBoxes, the JLabel’s output will be a concatenation of all items selected – thus we make this String an instance datum public static class GuiPanel extends JPanel implements ItemListener { // Buttons declared private JLabel lab; // as with GUI2 private String message; public GuiPanel() { message=""; lab=new JLabel(" "); b1.addItemListener(this); // ... for all 7 buttons JPanel whole=new JPanel(new BorderLayout()); whole.add(p1,BorderLayout.WEST); whole.add(p2,BorderLayout.EAST); whole.add(lab,BorderLayout.SOUTH); add(whole); } public void itemStateChanged(ItemEvent e) { if(e.getSource()==b1) message+="Option 1 selected "; if(e.getSource()==b2) message+="Option 2 selected "; if(e.getSource()==b3) message+="Option 3 selected "; if(e.getSource()==b4) message+="Option 4 selected "; if(e.getSource()==b5) message+="Selection a picked"; else if(e.getSource()==b6) message+="Selection b picked"; else if(e.getSource()==b7) message+="Selection c picked"; lab.setText(message); } } Scroll Bars and Scroll Panes • JScrollBars are added to JFrames – When you instantiate a scroll bar you specify its orientation (JScrollBar.HORIZONTAL or JScrollBar.VERTICAL) – You can also specify the starting value, its min and max values (if not specified, starting value by default is in the middle) • Scroll bars will generate AdjustmentEvents which are listened for by an AdjustmentListener – To implement an AdjustmentListener, implement the method adjustmentValueChanged • The problem with a scroll bar added to the JFrame is moving the view within the JFrame upon changing the scroll bar’s “knob” • Instead, we can also place our JPanel inside a scrollable component called a JScrollPane – this will be easier – Instantiate a JPanel for instance MyPanel p1 = new MyPanel( ); – Instantiate a JScrollPane using p1, JScrollPane jsp=new JScrollPane(p1); – Now the JPanel will have its own scroll bars if needed import java.awt.*; import javax.swing.*; public class ScrollExample1 { public static void main(String[] args) { // JFrame code omitted ScrollPanel p1=new ScrollPanel(); p1.setPreferredSize(new Dimension(250,100)); JScrollPane jsp=new JScrollPane(p1); frame.add(jsp); } public static class ScrollPanel extends JPanel { // code goes here for the JPanel // for instance, maybe we want to draw something: public void paintComponent(Graphics g) { // Graphics code goes here } } } JTextBox and JTextArea • Both extend JTextComponent • They have methods to setText, getText, isEditable and setEditable – You can also set lineWrap to allow line wrapping (if true) and use a wrapStyleWord to indicate if lines should be wrapped by word (if true) or character (if false) • The difference between these components is that the text area has multiple rows • You construct the text area using one of four constructors – – – – empty row, column size String – the area defaults to roughly the size of the String String, row, column size • Additional methods to a text area are to append a String, insert a String at a given index using jta.insert(String, index), replace a portion of the text with a new String using jta.replaceRange(String, start, end) and getLineCount public static class ScrollPanel extends Jpanel { private JLabel lab; private JTextArea jta; A JTextArea inside a JScrollPanel public ScrollPanel() { lab=new JLabel(""); JTextArea jta=new JTextArea(5,50); JScrollPane jsp=new JScrollPane(jta); jta.setLineWrap(true); jta.setWrapStyleWord(true); jta.getDocument().addDocumentListener(new DocumentListener(){ @Override public void changedUpdate(DocumentEvent e){ lab.setText("changing text"); } public void insertUpdate(DocumentEvent e) { lab.setText("inserting"); } public void removeUpdate(DocumentEvent e) { lab.setText("deleting"); } }); // insert jta and // lab into JPanel } } JComboBox • Drop down menus must be added to a JFrame rather than a JPanel so they are somewhat unusual and we will skip covering them • But Java does contain an alternate to a drop down menu – a JComboBox – The JComboBox allows you to select one item from a list of items – You define the list in an array of Objects when you instantiate the JComboBox • Upon selection, an ItemEvent and an ActionEvent are created so you can either implement an ItemListener (itemStateChanged) or ActionListener – The JComboBox can be implemented so that the entire list appears, only part of the list appears (along with a scroll bar) or a drop-down box appears public static class JCBPanel extends JPanel implements ItemListener{ private JLabel lab; private JComboBox box; private String[] list={//…}; private String[] descr={//…}; } public JCBPanel() { lab=new JLabel(" "); box=new JComboBox<String>(list); box.addItemListener(this); setLayout(new BorderLayout()); add(box,BorderLayout.CENTER); add(lab,BorderLayout.EAST); } public void itemStateChanged(ItemEvent e) { lab.setText(descr[box.getSelectedIndex()]); } Other JComboBox methods are: addItem(Object) getItemAt(int) getItemCount( ) getSelectedItem( ) – returns an Object removeItem(Object) removeItemAt(index) JList • The JList is similar to the JComboBox except that the List appears in a box (no drop down action needed) – The JList allows for multiple selections instead of the single selection of a JComboBox • the JList has an instance datum selectionMode which can be one of SINGLE_SELECTION, SINGLE_INTERVAL_SELECTION (you can select multiple items as long as they are contiguous in the list) and MULTIPLE_INTERVAL_SELECTION (multiple items whether contiguous or not) • the default is for multiple items (to select multiple items, hold down the control key while clicking, the shift key selects all items between last and current item in list) • If your JList is longer than the space in your JPanel, add the JList to a JScrollPane and insert the JScrollPane into your JPanel instead of the JList – This provides you a scroll bar as needed to view the whole list More on JList • The JList will use a ListSelectionListener (defined in javax.swing.event instead of java.awt.event) for any changes to the list (selecting or unselecting items) – Such a change generates a ListSelectionEvent – The ListSelectionListener must implement a valueChanged method • Since a JList can have multiple selected items, there are methods that return single Objects or ints (selected items, selected item indices) or arrays – single value methods: getMaxSelectionIndex, getMinSelectionIndex, getLeadSelectionIndex, getSelectedValue (returns the smallest index of the selected) – array methods: getSelectedIndices, getSelectedValues public void valueChanged(ListSelectionEvent e) { int[] x=list.getSelectedIndices(); for(int i=0;i<x.length;i++) // do something with x[i] } JSlider • The JSlider, which can be positioned horizontally or vertically, gives you an input for an int value between a min an max value – The JSlider is usually instantiated with min and max values, or min, max and the starting value of the slider (e.g., 0,100,50 would set the slider at 50) – Orientation is specified using JSlider.HORIZONTAL (the default) or JSlider.VERTICAL • you can also specify if tick marks should appear or not by setting paintTicks to true (defaults to false) and setting paintLabels to true (to print labels with the tick marks) – The JSlider creates a ChangeEvent which is handled by a ChangeListener through the stateChanged method – In this method, to determine the location of the slider, use slider.getValue( ) (where slider is the name of your object) import java.awt.*; import javax.swing.event.*; import javax.swing.*; public class JSL { public static void main(String[] args) { // omitted } public static class SliderPanel extends JPanel implements ChangeListener { private JSlider s1, s2, s3; private int red, green, blue; public SliderPanel() { red=0;green=0;blue=0; s1=new JSlider(0,255,0);s2=new JSlider(0,255,0); s3=new JSlider(0,255,0);s1.addChangeListener(this); s2.addChangeListener(this);s3.addChangeListener(this); JPanel p1=new JPanel(new GridLayout(3,1)); p1.add(s1); p1.add(s2); p1.add(s3); add(p1); } public void stateChanged(ChangeEvent e) { if(e.getSource()==s1) red=s1.getValue(); if(e.getSource()==s2) green=s2.getValue(); if(e.getSource()==s3) blue=s3.getValue(); repaint(); } public void paintComponent(Graphics g) {…} } } Controlling Multiple Windows • You can create and open/close other windows easily by declaring additional JFrames – Once a JFrame is created, use frame.setVisible(true); to open it and frame.setVisible(false); to close it • Let’s imagine that you want a program that can open another window on command (we will use JButtons to open and close a second window) – Create an instance datum in your JPanel (inner class) of type JFrame – In this inner JFrame class, define another JPanel • this JPanel will display the contents of the newly opened window, whatever that will be – In your JPanel, add two JButtons – For actionPerformed, one button will set the inner class’ JFrame to visible and the other will set the inner class’ JFrame to not visible public static class ButtonPanel extends JPanel implements ActionListener { private JFrame second=new JFrame(); private SecondPanel sp=new SecondPanel(); private JButton b1, b2; public ButtonPanel(){ second.setSize(new Dimension(200,200)); second.add(sp); b1=new JButton("open second window"); b2=new JButton("close second window"); b1.addActionListener(this); b2.addActionListener(this); add(b1); add(b2); } public void actionPerformed(ActionEvent e){ if(e.getSource()==b1) second.setVisible(true); else if(e.getSource()==b2) second.setVisible(false); } private class SecondPanel extends JPanel{ public void paintComponent(Graphics g) { g.setColor(Color.green); g.fillRect(0,0,200,200); } }