Building Graphical User Interfaces 5.0
2 Overview Constructing GUIs Interface components GUI layout Event handling Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
3 GUI Principles Components: GUI building blocks –Buttons, menus, sliders, etc Layout: arranging components to form a usable GUI –Using layout managers Event handling: reacting to user input –Button presses, menu selections, etc Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
4 GUI libraries AWT and Swing Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling AWT (Abstract Window Toolkit): original Java API Swing: use some AWT, replace some AWT, and adds many new classes
5 Elements of a frame Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
6 Creating a frame Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling import java.awt.*;// import 3 packages import java.awt.event.*;// completely for GUI import javax.swing.*;// Swing applications public class ImageViewer { private JFrame frame; // variable holds the frame /** * Create an ImageViewer show it on screen. */ public ImageViewer() { makeFrame(); // handling GUI construction } // rest of class omitted. }
7 The content pane Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling /** * Create the Swing frame and its content. */ private void makeFrame() { frame = new JFrame("ImageViewer"); // creates new frame Container contentPane = frame.getContentPane();// gets Content Pane JLabel label = new JLabel(”I am a label. I can display some text."); contentPane.add(label); // label created and added to Content Pane frame.pack(); // arranges frame components & resizes frame.setVisible(true); // makes frame visible after construction }
8 Adding menus JMenuBar –Displayed below the title –Contains the menus JMenu –( e.g. File) Contains the menu items JMenuItem –( e.g. Open) Individual items Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
9 private void makeMenuBar(JFrame frame) { JMenuBar menubar = new JMenuBar(); frame.setJMenuBar(menubar); JMenu fileMenu = new JMenu("File"); // create File menu menubar.add(fileMenu); // add to menubar JMenuItem openItem = new JMenuItem("Open"); // create Open item fileMenu.add(openItem); // add to File menu JMenuItem quitItem = new JMenuItem("Quit"); // create Quit item fileMenu.add(quitItem); // add to File menu } The menu bar
10 Event handling Events correspond to user interactions with components Components are associated with different event types –Frames are associated with WindowEvent i.e. frame closed or iconified –Menus are associated with ActionEvent i.e. button clicked or menu item selected –Mouses are associated with MouseEvent i.e. mouse clicked or moved Objects can be notified when event occurs –Such objects are called listeners Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
11 Centralized event receipt A single object handles all events –Implements the ActionListener interface –Defines an actionPerformed method It registers as a listener with each component –item.addActionListener(this) It has to work out which component has dispatched the event Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
12 ActionListener public interface ActionListener { public void actionPerformed(ActionEvent e); } public class ImageViewer implements ActionListener { … public void actionPerformed(ActionEvent e) { String command = e.getActionCommand(); if(command.equals("Open")) { … } else if (command.equals("Quit")) { … } … } … private void makeMenuBar(Jframe frame) { … openItem.addActionListener(this); … } Makes ImageViewer object a single listener to all menu events:
13 Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling public class ImageViewer implements ActionListener {// ensures object is a subtype of ActionListener … public void actionPerformed(ActionEvent e) { String command = e.getActionCommand(); if(command.equals("Open")) { … } else if (command.equals("Quit")) { … } … } … private void makeMenuBar(Jframe frame) { … openItem.addActionListener(this); … // registers ImageViewer object as } // a listener for the menu item }
14 JMenuItem openItem = new JMenuItem(“Open”); openItem.addActionListener(this); Registering as a listener Menu item openItem is created –new JMenuItem(“Open”) Current object ImageViewer is registered as an action listener by passing this –addActionListener(this) public void actionPerformed(ActionEvent e) Activated menu item within a registered listener object will: –invoke own actionPerformed method –menu item passes parameter ActionEvent e °event details ( i.e. time, key states, command string, …) °command string identifies component that caused event >event.getActionCommand() retrieves command string
15 Centralized event handling The approach works It is used, so you should be aware of it However … –It does not scale well –Identifying components by their text is fragile –Maintenance and expandability difficult An alternative approach is preferred Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
16 Inner classes Class definitions may be nested Instances of inner class are localized inside the enclosing class –inner class can only exist within enclosing instance Instances of inner class have access to private fields and methods of the enclosing class –tightly coupled inner class considered part of the enclosing class (just like enclosing class’s methods) public class Enclosing { … private class Inner { … }
17 actionPerformed method class ImageViewer { // style guides inner classes written at the end … class OpenActionListener implements ActionListener { public void actionPerformed(ActionEvent event) { // perform open action } class QuitActionListener implements ActionListener { public void actionPerformed(ActionEvent event) { // perform quit action } Now create inner class instances the same way as any other class JMenuItem openItem = new JMenuItem(“Open”); openItem.addActionListener(new OpenActionListener()); … JMenuItem quitItem = new JMenuItem(“Quit”); quitItem.addActionListener(new QuitActionListener()); ImageView no longer implements ActionListener & actionPerformed is now implemented by inner classes
18 actionPerformed method JMenuItem openItem = new JMenuItem(“Open”); openItem.addActionListener(new OpenActionListener()); … JMenuItem quitItem = new JMenuItem(“Quit”); quitItem.addActionListener(new QuitActionListener()); Separate listener object for each possible event Each listener listens to only one single event type Each listener has its own actionPerformed method –specific handling code for that event only –makes full use of enclosing class’s private fields & methods Only menu items have a reference to the listener object! Only a single object created from the specialized inner class! Listener objects NOT stored in variables … Anonymous Objects
19 Anonymous inner classes Obey the rules of inner classes Uses inner class exactly once to create a single, unnamed instance of the object Same as defining separate named classes for the listeners, but NO class name is required Listener methods are now closer to the listener registration of the menu item Anonymous class has access to fields & methods of the enclosing class Also, access to local variables & parameters of method that the class is defined inside of –BUT, local variables must be declared FINAL Uses a special syntax
20 Anonymous class elements Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling openItem.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { openFile(); } ); Anonymous object creation Actual parameter Class definition
21 Anonymous action listener JMenuItem openItem = new JMenuItem("Open"); openItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) {openFile();} } ); Syntactical shortcut in one statement to: Define unnamed class with its superclass type –body of class between the outer braces { } –includes implementation for its abstract methods °method definition and {action body} if event occurs Create an object of the anonymous class –using new to create the single instance Pass object to menu item’s addActionListener –in the (parameter) to register the object as an action listener for the menu item … where °openFile( ) of enclosing class is invoked when activated
22 BlueJ Scope coloring Green = class Yellow = method definition = method body
23 Anonymous inner classes Cohesion –creates separate custom-made action listeners for each individual menu item –directly calls method implementing the corresponding function for the even Extendability –removed central actionPerformed method which implemented functions for all the menu items –adding additional menu items is localized Harder to read –use only for very short classes Often used when only 1 instance of the implementation is required –associated actions unique to that particular item –instance always referred to via its supertype °less need for a name … hence it is anonymous
24 Exit on window close Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); WindowAdapter provides a no-operation implementation of the WindowListener interface. It then allows implementation of methods for only the events you care about.
25 The imageviewer project Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
26 Image processing Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
27 Class responsibilities ImageViewer –Sets up the GUI structure ImageFileManager –Static methods for image file loading and saving ImagePanel –Displays the image within the GUI OFImage –Models a 2D image Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
28 Class OFImage Custom format representing an image in memory as a 2D array of pixels Our subclass of BufferedImage –from package java.awt.image –gives necessary functionality except set/get pixel using a Color object Important methods: –read/modify pixels: getPixel, setPixel –find image size: getWidth, getHeight Each pixel has a color –represented by java.awt.Color Treat like a library class
29 Class ImageFileManager Offers 3 methods: –one reads a named image file from disk and return it as an OFImage –one writes an OFImage file to disk –one opens a file-chooser dialog for user to select an image to open Methods can: –read files in standard JPEG & PNG formats –write files in JPEG format Done using standard Java image I/O methods from ImageIO class: –package javax.imageio
30 Class ImagePanel Implements custom-made Swing components to display the image –custom components easily created with a subclass of an existing component –then, inserted into a Swing container and displayed in our GUI like another component ImagePanel is a subclass of JComponent –method setImage takes OFImage as a parameter to display any given OFImage Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
31 Adding an ImagePanel Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling public class ImageViewer { private JFrame frame; private ImagePanel imagePanel; … private void makeFrame() { Container contentPane = frame.getContentPane(); imagePanel = new ImagePanel(); contentPane.add(imagePanel); } … } In makeFrame, create & add ImagePanel component instead of previous JLabel –instance of ImagePanel object stored in a field for access later
32 Loading an image public class ImageViewer { private JFrame frame; private ImagePanel imagePanel; … private void openFile() { File selectedFile = …; OFImage image = ImageFileManager.loadImage(selectedFile); imagePanel.setImage(image); frame.pack(); } … } Now openFile actually opens & displays an image file using our image-processing classes –ImageFileManager can select & open image –ImagePanel can display that image –frame.pack necessary with image size change recalculates frame layout and redraws frame
33 Layout managers Swing uses layout managers to arrange the layout of components in a GUI –each Container ( i.e. content pane) has an associated layout manager to take care of arranging the components within itself Manage limited space for competing components –FlowLayout, BorderLayout, GridLayout, BoxLayout, GridBagLayout Each imposes its own style –components are positioned differently –available space distributed differently
34 FlowLayout Arranges all components left to right Centers horizontally –if there is not enough horizontal space, it wraps around to a second line Leaves components its preferred size Thus, NO spare space around components if window is resized
35 BorderLayout Places up to 5 components in arranged pattern –space distributed (unevenly) between components Each of these positions may be empty (<=5) No leftover space if window is resized –CENTER(center) = stretches in both height & width –NORTH (top) = keeps height & stretches in width –SOUTH (bottom) = “ –EAST (right) = stretches in height & keeps width –WEST (left) = “
36 GridLayout Lay out components in an evenly spaced grid –specified number of rows & columns All components always kept the same size Useful to keep buttons the same width –JButton width initially determined by text on button –button insertion into GridLayout results in ALL buttons resized to width of the widest button Odd number of equal-sized grid components –may result in spare space
37 BoxLayout NOTE: No component resizing Lay out components vertically or horizontally Components are not resized Layout will not wrap when resized Nesting multiple BoxLayouts inside each other –sophisticated 2-dimensionally aligned layouts
38 Nested containers Sophisticated layouts by nesting containers –many Swing components are containers –such as JFrame, JPanel, JWindow, … Containers may contain multiple components –such as JPanel, JLabel, JButton, … JPanel container is most often used –insert as a component in the frame’s content pane –with more components laid out inside the JPanel buttons, labels, etc… –each may have its own layout Container & layout manager work together –container holds components –layout manager decides exact arrangement Each container has its own layout manager –BorderLayout, FlowLayout, GridLayout, BoxLayout, … –each container has different default (if not set) JFrame = BorderLayout JPanel = FlowLayout
39 Nested containers CENTER –ImagePanel (user-defined in ImageViewer) NORTH –JPanel (FlowLayout - horizontal) 4 toolbar button components SOUTH –JPanel (FlowLayout - horizontal) 3 object components WEST –JPanel (FlowLayout - vertical) JPanel (GridLayout - 1 column) °4 button components EAST –unused Interface arrangement similar to the BlueJ Main Window Content Pane (BorderLayout)
40 ImageViewer example CENTER –ImagePanel (user-defined in ImageViewer) NORTH –JLabel: image filename SOUTH –JLabel : status text WEST –unused EAST –unused Content Pane (BorderLayout)
41 ImageViewer example setLayout used on contentPane to set layout manager –layout manager itself is the object –create instance of BorderLayout to pass to setLayout Container component with BorderLayout set differently –overloaded add method has 2nd parameter with public constant defined in the BorderLayout class °NORTH, SOUTH, EAST, WEST or CENTER
42 Glue, Rigid Areas & Struts Invisible components used as spacing Available from the Box class Glue: fills available space –Component createHorizontalGlue() –Component createVerticalGlue() Rigid Area: fixed size (horizontal AND vertical) –Component createRigidArea(new Dimension(20,0))); Strut: fixed size (horizontal OR vertical - 1 direction) –Component createHorizontalStrut(int width) –Component createVerticalStrut(int height) NO spacing between buttons Glue stretchy & expandable Rigid fixed-sized space between buttons
43 Dialogs Modal dialogs block all other interaction –Forces a response from the user Non-modal dialogs allow other interaction –This is sometimes desirable –May be difficult to avoid inconsistencies Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling Pop-up informational display
44 JOptionPane standard dialogs Message dialog –Message text –OK button to confirm Confirm dialog –Asks a question –Yes, No, Cancel button options Input dialog –Message prompt –Input text field Variations are possible Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
45 A message dialog Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling private void showAbout() { JOptionPane.showMessageDialog(frame, "ImageViewer\n" + VERSION, "About ImageViewer", JOptionPane.INFORMATION_MESSAGE); }
46 Displaying text JLabel –short text string display area –usually not editable JTextField –single line display area for plain text –allows editing JTextArea –multi-line display area for plain text –allows editing –make scrollable within a JScrollPane
47 Image filters First step toward image manipulation Function applied to the whole image –darker: makes whole image darker –lighter: makes whole image lighter –threshold: turns image into grayscale (3-levels) °white = upper-third pixel value range °black = lower-third pixel value range °gray = middle third Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
48 ImageViewer example Menu items for each filter with a menu listener –new JMenu named Filter added to the menu bar °added new JMenuItems named Darker, Lighter, & Threshold >new ActionListoner anonymous class for each menu item ~invoking makeDarker, makeLighter, & threshold upon event Implement each actual filter operation –simple filter iterate over entire image –make change of some sort to the color of each pixel –more complicated filters may use neighboring pixel value int height = getHeight(); int width = getWidth(); for(int y = 0; y < height; y++) { for(int x = 0; x < width; x++) { Color pixel = getPixel(x, y); alter the pixel's color value; setPixel(x, y, pixel); }
49 Adding further filters Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling private void makeLighter() { if(currentImage != null) { currentImage.lighter(); frame.repaint(); showStatus("Applied: lighter"); } else { showStatus("No image loaded."); } private void threshold() { if(currentImage != null) { currentImage.threshold(); frame.repaint(); showStatus("Applied: threshold"); } else { showStatus("No image loaded."); } Code duplication in activation methods? Refactor!
50 imageviewer2-0 Define a Filter superclass (abstract) Create function-specific subclasses Create subclass instances in ImageViewer Define a generic applyFilter method
51 Buttons and nested layouts GridLayout in FlowLayout in BorderLayout FlowLayout leaves space GridLayout (0,1) in BorderLayout GridLayout resizes In BorderLayout FlowLayout default 2 instances of JButton in the WEST area
52 Borders Adds decoration around components Used to group components or add space Every Swing component can have borders Some layout managers have border parameters to create requested spacing Defined in javax.swing.border –BevelBorder, CompoundBorder, EmptyBorder, EtchedBorder, TitledBorder Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling
53 Adding spacing JPanel contentPane = (JPanel)frame.getContentPane(); contentPane.setBorder(new EmptyBorder(12, 12, 12, 12)); // Specify the layout manager with nice spacing contentPane.setLayout(new BorderLayout(6, 6)); imagePanel = new ImagePanel(); imagePanel.setBorder(new EtchedBorder()); contentPane.add(imagePanel, BorderLayout.CENTER); Add empty space around outside of frame –setBorder of content pane with EmptyBorder parameter –cast the contentPane to a JPanel °supertype Container does not have setBorder method Add extra spacing around the frame components –by creating BorderLayout with 2 int parameters Add an “ etched” line around the image (CENTER) –setting an EtchedBorder for imagePanel
54 Add empty space around outside of frame –JPanel contentPane = (JPanel)frame.getContentPane(); –contentPane.setBorder(new EmptyBorder(12, 12, 12, 12)); Add extra spacing around the frame components –contentPane.setLayout(new BorderLayout(6, 6)); Add an “ etched” line around the image (CENTER) –imagePanel.setBorder(new EtchedBorder()); AfterBefore
55 Other components Slider –allows user to easily enter a numeric value bounded by a minimum and maximum value Spinner –allows user to choose via arrows or keys from a range of values (does not wrap around min-max values) –can also automatically complete user typed input Tabbed pane –allows several components ( i.e panels) share the same space –user chooses component by selecting corresponding tab Scroll pane –provides a scrollable view of a component
56 Programming GUI with Swing Many different types of components, containers and layout managers –each has many attributes and methods Covered important concepts with details –still large amount of functionality beyond our scope Many sources of information to further discover –API documentation for the Swing classes –Oracle Java Swing Tutorial °
57 Review Aim for cohesive application structures –Endeavor to keep GUI elements separate from application functionality Pre-defined components simplify creation of sophisticated GUIs Layout managers handle component juxtaposition –Nest containers for further control Many components recognise user interactions with them Reactive components deliver events to listeners Anonymous inner classes are commonly used to implement listeners