Grafiska användargränssnitt i Java jonas.kvarnstrom@liu.se – 2015 Komponenter: Fönster, knappar, menyer, färgväljare och andra grafiska element som syns på skärmen (components) Behållare: De komponenter som innehåller andra komponenter – till exempel fönster (containers) SwingSet3: finns på nätet 2 jonkv@ida Terminologi 3 Java Foundation Classes (JFC) AWT: Abstract Window Toolkit Swing Java 2D Koppling till OS Layout Händelsehantering Enkla komponenter Uppdaterade och mer avancerade GUIkomponenter 2D-grafik (linjer, rektanglar, kurvor, färger, mönster, …) Komponenter: Frame, Button, List, TextField, … Komponenter: JFrame, JButton, JList, JTextField, … Använd inte – föråldrade! Använd dessa! jonkv@ida Java Foundation Classes Steg 1 (idag): Att använda färdiga komponenter: Knappar, menyer, … Layout Händelsehantering – ”någon tryckte en knapp" Steg 2 (nästa gång): Att rita på skärmen Att skapa egna komponenter Mål: En väldigt enkel ”ordbehandlare” (texteditor) 6 jonkv@ida Genomgående exempel Ett vanligt fönster: JFrame ▪ public class WordProcessor { private JFrame frame; 8 http://docs.oracle.com/javase/tutorial/ uiswing/components/frame.html Ordbehandlaren behöver ”komma ihåg” sitt fönster public WordProcessor() { this.frame = new JFrame("Word Processor 1.0"); frame.setSize(640, 300); Sätt fönsterstorleken, frame.setVisible(true); se till att fönstret visas på skärmen } public static void main(String[] args) { new WordProcessor(); } } Skapa ett objekt, glöm bort det, och sedan är vi klara? Så länge det finns ett öppet fönster, avslutas inte Java! Vi kan fortfarande använda fönstret genom GUI-händelser (events) Ta reda på skärmens storlek: ▪ frame.getToolKit().getScreenSize() jonkv@ida Att öppna ett fönster 10 En JFrame är en behållare (container) http://docs.oracle.com/javase/tutorial/ uiswing/components/frame.html Komponent som kan innehålla andra komponenter Kan även innehålla andra behållare Fönstertitel Menyrad Kan läggas till vid behov Innehåll: Content pane Hela fönstrets innehåll. utom titelrad / menyrad jonkv@ida Behållare 1: JFrame 11 jonkv@ida Behållare 2: Innehållshierarki Skapar en hierarki av innehåll Varje behållare har en lista med barn Fönster Menyrad Meny: File Val1 Val2 Meny: Edit Val3 ContentPane Meny: Help Knapp1 Knapp2 Textfält Har inget att göra med arvshierarkin! Statusrad 12 jonkv@ida Knappar i Java http://docs.oracle.com/javase/tutorial/ uiswing/components/button.html http://docs.oracle.com/javase/tutorial/ uiswing/components/buttongroup.html Stödklasser Grunden för Swing-komponenter Gemensam implementation: Knappar Har två lägen, av/på Radioknappar: Bara en aktiv åt gången i varje ButtonGroup Standardknapp Checkbox, av/på 13 http://docs.oracle.com/javase/tutorial/ uiswing/components/text.html Abstrakt, gemensam funktionalitet Editera text med flera stilar: HTML, … En enda rad text Textarea med flera rader Speciell formattering för datum, valuta, … Lösenord syns inte när de skrivs in jonkv@ida Textkomponenter 14 http://docs.oracle.com/javase/tutorial/ uiswing/components/label.html För att lägga till komponenter: ▪ public WordProcessor() { this.frame = new JFrame("Word Processor 1.0"); frame.add(new JButton("B")); frame.add(new JButton("I")); frame.add(new JButton(“U”)); frame.add(new JButton(“Left")); frame.add(new JButton(“Center")); frame.add(new JButton(“Right")); Lägger till flera komponenter till behållaren – fönstret Inget syns på skärmen än! frame.add(new JTextPane()); frame.add(new JLabel("Status: OK")); // Visar text, kan inte editeras frame.pack(); frame.setVisible(true); } NU är det dags att visa fönstret och dess innehåll jonkv@ida Ordbehandlare med komponenter 15 Resultat: Rätt komponenter Liten textarea Fel layout JFrame Content Pane JButton JButton JButton JButton JButton JTe xtP ane JLabel jonkv@ida Resultat 17 Önskad layout (positioner och storlek): JFrame Content Pane JButton JTextPane JLabel JButton JButton JButton JButton jonkv@ida Önskad layout 18 Hur ska behållarens komponenter få rätt position och storlek? Enklast: Absoluta koordinater ▪ component.setSize(int width, int height); ▪ component.setLocation(int x, int y); // Relativt behållarens övre vänstra hörn Fördelar / nackdelar: ▪ (+) Enkelt att förstå ▪ (+) Enkelt att skriva GUI-designer ▪ (–) Inget stöd för att ändra storlek (Gammaldags Windows-dialoger har alltid en fast storlek…) ▪ (–) Hur hanterar man större text? ▪ (–) Hur hanterar man översättningar till andra språk, där ord kan ta mer plats? jonkv@ida Layout 1: Absoluta koordinater? Preferred Size 19 http://docs.oracle.com/javase/tutorial/ uiswing/layout/index.html Komponenter kan tala om sin önskade storlek (preferred size) JButton: Storlek på texten i inställd fontstorlek + lite marginaler Ingen text inskriven preferred size är minimal! Varje behållare har en layouthanterare (layout manager) Frågar subkomponenter hur stora de vill vara Applicerar layoutregler (här: "Allt i en rad") Summerar, beräknar behållarens önskade storlek jonkv@ida Layout 2: Önskad storlek 20 jonkv@ida Layout 3: Innehållshierarkin Anropa pack() i ett fönster (frame)… …Så frågar den sin layouthanterare hur mycket plats den behöver använd den storleken! Fönster Menyrad Meny: File Val1 Val2 Meny: Edit Val3 ContentPane Meny: Help Knapp1 Knapp2 Textfält Statusrad 21 När en komponent får större storlek än den begärda: Layouthanteraren har regler för hur utrymmet ska användas Extra utrymme på höjden: Ska användas till textarean Extra utrymme på bredden: Menyrad: Extra plats mellan Edit och Help Knapprad: Allt vänsterjusterat Textfält, statusrad: Använder hela utrymmet Just nu: jonkv@ida Layout 4: Annan storlek än önskad När en komponent får mindre storlek än den begärda: Layouthanteraren har regler för hur komponenter placeras, (krymps) Just nu: 22 jonkv@ida Layout 5: Annan storlek än önskad 23 Flera enkla layouthanterare är inbyggda Save changes before exiting? Yes No Cancel Hur kan man skapa en mer komplex layout med dessa? jonkv@ida Layouthanterare 1: ”Inbyggda” 24 JFrame Använd hierarkin! Lägg till en panel så att alla knappar är i en egen ”grupp” JPanel jonkv@ida Layouthanterare 2: Hierarkisk layout JMenu JMenu JMenuBar JMenu Content Pane JButton JButton JButton JButton JButton JPanel JTextPane JLabel Fönster Menyrad Meny1 Val1 Val2 ContentPane Panel Meny2 Val3 Knapp1 Knapp2 Textfält Statusrad MigLayout – rekommenderas starkt! Baseras på flexibelt rutnät, modern, extremt flexibel ▪ this.setLayout(new MigLayout()); this.add(firstNameLabel); this.add(firstNameTextField); this.add(lastNameLabel, "gap unrelated"); this.add(lastNameTextField, "wrap"); this.add(addressLabel); this.add(addressTextField, … 25 Default: Använder preferred size; fortsätter på samma rad; lägger till ett mellanrum som passar relaterade komponenter Mellanrum för två orelaterade komponenter Ny rad efter den här komponentent "span 3, grow"); Spänn över 3 kolumner, låt textfältet växa större än sin önskade storlek Layoutparametrar för varje komponent http://www.miglayout.com/QuickStart.pdf http://www.migcalendar.com/miglayout/mavensite/docs/cheatsheet.html jonkv@ida Layouthanterare 3: MigLayout Kodskelett: ▪ public class WordProcessor { private JTextPane text; // References to some components private JLabel status; // that we will have to access at various times private JFrame frame; public WordProcessor() { this.frame = new JFrame("Word Processor 1.0"); createGUI(); // Adds components to the frame createMenus(); // Adds menus frame.pack(); // Adapt window size frame.setVisible(true); // Show the window! } public static void main(String[] args) { new WordProcessor(); } } 26 jonkv@ida Ordbehandlaren 1: Ett skelett 27 Knappar ligger i sin egen panel Inte ett krav med MigLayout! Men låter oss ta bort och lägga till knappar utan att påverka resten: Huvudfönstrets layouthanterare ser alltid “en panel” ▪ private JPanel createButtonPanel() { final JPanel buttons = new JPanel(); buttons.setLayout(new MigLayout()); buttons.add(new JButton("B")); buttons.add(new JButton("I")); buttons.add(new JButton("U")); buttons.add(new JButton("Left"), “gapleft 10pt”); buttons.add(new JButton("Center")); buttons.add(new JButton("Right")); } buttons.add(new JButton("Print"), “gapleft 10pt”); return buttons; Separation 10 punkters marginal till vänster om komponenten jonkv@ida Ordbehandlaren 2: Skapa knappar ▪ private void createGUI() { frame.setLayout(new MigLayout( “”, “[grow,fill]”, “[]0[grow,fill]0[]” )); … } Vårt mål… 28 Layoutparametrar Inget här… Kolumnparametrar Varje kolumn anges i [] Kolumnen kan växa (grow), och ska alltid fylla (fill) tillgängligt utrymme Radparametrar Första raden: [] (default) Mellanrum: 0 pixel Andra raden: Grow, fill Mellanrum: 0 pixel Tredje raden: [] (default) jonkv@ida Ordbehandlaren 3: Sätta layouthanterare 29 jonkv@ida Ordbehandlaren 4: Ramar Alla komponenter kan ha en ram, som implementerar gränssnittet Border. Använd BorderFactory för vanliga ramtyper. ▪ private void createGUI() { frame.setLayout(new MigLayout(…)); = new JTextPane(); this.text this.status = new JLabel("Status: OK"); text.setBorder(BorderFactory.createEmptyBorder(4,4,4,4)); status.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createEtchedBorder(), BorderFactory.createEmptyBorder(2,2,2,2) )); EmptyBorder = tomt utrymme (marginaler) CompoundBorder sätter ihop ramar: Ytterst en etsad ram Innerst en marginal http://docs.oracle.com/javase/tutorial/ uiswing/components/border.html 30 jonkv@ida Ordbehandlaren 5: Scrollning http://docs.oracle.com/javase/tutorial/ uiswing/components/scrollpane.html Textfältet måste kunna scrollas I vissa system: "Inbyggt" i textfältet I Java: Lägg komponenten i en JScrollPane ▪ Samma hantering av scrollning för alla komponenter ▪ private void createGUI() { … frame.add(createButtonPanel(), “wrap”); frame.add(new JScrollPane(text), “wrap”); frame.add(status, “wrap”); } Fönster Menyrad Meny1 Val1 Val2 ContentPane Meny2 Val3 Panel Knapp1 Knapp2 JScrollPane Statusrad Textfält ▪ private void createMenus() { final JMenu file = new JMenu("File"); file.add(new JMenuItem("Open", 'O')); file.add(new JMenuItem("Save As", 'A')); file.addSeparator(); file.add(new JMenuItem("Print")); 32 http://docs.oracle.com/javase/tutorial/ uiswing/components/menus.html, separator.html // Tangentbordsstyrning // Separator final JMenu edit = new JMenu("Edit"); edit.add(new JMenuItem("Cut")); edit.add(new JMenuItem("Copy")); edit.add(new JMenuItem("Paste")); final JMenu help = new JMenu("Help"); help.add(new JMenuItem("About WordProcessor 1.0")); final JMenuBar bar = new JMenuBar(); bar.add(file); bar.add(edit); bar.add(Box.createHorizontalGlue()); bar.add(help); frame.setJMenuBar(bar); } Separering Skapar en osynlig komponent, 0 pixel hög, godtyckligt bred jonkv@ida Att skapa menyer TDDC69 2011-2013: Allt på engelska Använd tid för kursutveckling på bästa sätt… TDDD78 2014-2015: Inledande fö. på svenska TDDD78 2014-2015: Resten på engelska Nästan helt omskrivet, många fundamentala begrepp Många justeringar, huvudstrukturen behålls How do we know if a button was pushed? TDDD73: Wait for a click ▪ Must know when to check ▪ Must handle everything ourselves – coordinates, … 35 jonkv@ida Event Handling Principles 36 In some GUI systems: Tell the system what it should do when the button is clicked Go on with your own task When the button is pushed, another thread handles this asynchronously (Almost) as if: You tell someone else: "If the button is pressed, do this" Your assistant starts looking for input You keep doing whatever you want to do next Sees a button was pressed, does what you asked jonkv@ida Event Handling Principles (2) 37 How to represent what happens and what to do about it? As event objects [händelseobjekt]… // Standard Java class public class MouseEvent extends InputEvent { int x; // Coordinates int y; int clickCount; // How many times did they click? int button; // With which mouse button? … } Button clicked Our "assistant" creates a new MouseEvent jonkv@ida Event Handling Principles (3) How to represent what happens and what to do about it? Could we tell the component which function to call? // Would work in some languages… function printMessage() { print "Hey! Someone clicked me!" } button.whenClicked(printMessage); Java is object-oriented, has no functions outside classes Java 8 has new ”magic syntax” that lets us do something similar To see what really happens, and to link this to interesting design patterns, we will avoid this syntax for now! 38 jonkv@ida Event Handling Principles (4) 39 jonkv@ida Event Handling Principles (5) How to represent what happens and what to do about it? We'll give the button an object whose methods it can call! // Standard Java interface public interface MouseListener extends EventListener { public void mouseClicked(MouseEvent e); Java is manifestly typed, public void mousePressed(MouseEvent e); must define a type … for the object … } We create a class implementing MouseListener // Our own class public class MyListener implements MouseListener { public void mouseClicked(MouseEvent e) { System.out.println("Hey! Someone clicked me!"); We give our "assistant" } a MyListener object } whose methods it can call when something happens Every component has a list of Listeners // (This is a simplification…) public class Component { private List<MouseListener> mouseListeners; public void addMouseListener(MouseListener ml) { mouseListeners.add(ml); } … } We can add our own listener to the list // Our own class public class MyGUI { public void createGUI() { MouseListener ml = new MyListener(); theButton.addMouseListener(ml); } } 40 jonkv@ida Event Handling Principles (6) When a mouse button has been pressed: AWT receives ”raw” keyboard/mouse input from the OS In a background event dispatch thread (your "assistant") Generates low-level event objects: MouseEvent, KeyEvent public class MouseEvent extends InputEvent { int x; // Coordinates int y; int clickCount; // How many times did they click? int button; // With which mouse button? … } 41 jonkv@ida Events 1: Introduction When a button has been pressed: AWT receives ”raw” keyboard/mouse input from the OS In a background event dispatch thread (your "assistant") Generates low-level event objects: MouseEvent, KeyEvent Asks the relevant component to process the event Mouse click sent to component that was clicked // AWT finds out which component is responsible MouseEvent event = …; Component comp = findOutWhoWasClicked(); // AWT asks the component to take care of the event comp.processEvent(event); 42 jonkv@ida Events 2: Introduction 43 When a button has been pressed: Asks the relevant component to process the event Mouse click sent to component that was clicked Event processing notifies (calls a method in) every listener Including our registered MyListener public class Component { protected void processMouseEvent(MouseEvent event) { for (MouseListener listener: MouseListeners) { if (event.getID() == MouseEvent.MOUSE_PRESSED) listener.mousePressed(e); One event at a time! … } If your listener takes a long time, } the UI will freeze. If so, } let the listener start a thread! jonkv@ida Events 3: Introduction Uses a design pattern called Observer! Components are observable, can tell others when something happens Listeners are observers, observing specific event types 44 jonkv@ida Events 4: Design Pattern 45 How are listeners used? ▪ public class WordProcessor { private JTextPane text; … public JPanel createButtonPanel() { Create local variables final JPanel buttons = new JPanel(); for the buttons, final JButton bold = new JButton("B"); so you can refer to buttons.setLayout(…); them later! buttons.add(bold); bold.addActionListener(new BoldListener(text)); } } ▪ public class BoldListener implements ActionListener { private final JTextPane pane; public BoldListener(JTextPane pane) {this.pane = pane;} A lot of trivial code around public void actionPerformed(ActionEvent event) { “the real work” // … Make the selected text bold … } Called by the event system in the } event dispatch thread when Bold is pressed jonkv@ida WP Events 1: Top-Level Class 46 jonkv@ida WP Events 2: Inner Class Alternative: Inner Class ▪ public class WordProcessor { private JTextPane text; … public JPanel createButtonPanel() { final JPanel buttons = new JPanel(); final JButton bold = new JButton("B"); buttons.setLayout(…); buttons.add(bold); class BoldListener implements ActionListener { public void actionPerformed(ActionEvent event) { foo(text.getText()); // … Make the text bold … } } bold.addActionListener(new BoldListener()); } } Define a class inside another – even inside a method! Gives access to fields of the enclosing class, final local variables of the method We still need a name… 47 Alternative: Anonymous Inner Class ▪ public class WordProcessor { private JTextPane text; … public JPanel createButtonPanel() { final JPanel buttons = new JPanel(); final JButton bold = new JButton("B"); buttons.setLayout(…); buttons.add(bold); ActionListener al = new ActionListener() { public void actionPerformed(ActionEvent event) { foo(text.getText()); // … Make the text bold … } Special “syntactic sugar”! }; bold.addActionListener(al); 1) Declares an unnamed class } implementing ActionListener } 2) Gives it an implementation for actionPerformed() 3) Creates a new object of this unnamed class jonkv@ida WP Events 3: Anonymous 48 First alternative: One listener per button bold.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { System.out.println("Bold"); You know where the event } came from – the bold button }); italics.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { System.out.println("Italics"); A little bit of overhead } from defining many classes }); // ... and so on ... jonkv@ida WP Events 4: One Listener per Button 49 Second alternative: A combined listener class final ActionListener al = new ActionListener() { public void actionPerformed(ActionEvent e) { if (e.getSource() == bold) { Since many components share System.out.println("Bold"); listeners, you must } else if (e.getSource() == italics) { check the source System.out.println("Italics"); of each event } } }; bold.addActionListener(al); italics.addActionListener(al); // ... and so on ... } return buttons; jonkv@ida WP Events 5: A Shared Listener Class 50 Alternative for actions that can be triggered from many places: Use Action (interface) and AbstractAction (helper class)! ▪ Action boldAction = new AbstractAction("Action Name") { // Instance initializer to set some (optional) values { putValue(SHORT_DESCRIPTION, "Tool Tip Text"); putValue(SMALL_ICON, new ImageIcon("icon.gif")); putValue(MNEMONIC_KEY, new Integer(KeyEvent.VK_A)); //underlined putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke("control F2")); } public void actionPerformed(ActionEvent evt) { http://docs.oracle.com/javase/tutorial/ // Perform action uiswing/misc/action.html } }; Many components can be constructed from an action object ▪ panel.add(new JButton(boldAction)); editMenu.add(boldAction); toolbar.add(boldAction); jonkv@ida Actions Event handling for menus: No difference in principle final JMenuItem open = new JMenuItem("Open"); fileMenu.add(open); open.addActionListener(…); 51 jonkv@ida Menu Events Some of the most important listeners: ▪ ActionListener Button pushed, menu item selected, … ▪ AdjustmentListener Slider or scroll bar adjusted ▪ ItemListener Items selected in list ▪ MouseListener Mouse button pushed/released, … ▪ MouseMotionListener Mouse pointer moved ▪ KeyListener Key pressed, typed, released Sent to the component that has keyboard focus If not processed, passed on to its container, etc. To react directly to keyboard input, see: http://docs.oracle.com/javase/tutorial/uiswing/misc/keybinding.html http://docs.oracle.com/javase/tutorial/uiswing/events/keylistener.html 52 jonkv@ida Event Listener Overview A simpler replacement for key listeners KeyStroke: A combination of keys (X, Ctrl-Shift-Z, …) Each component's InputMap maps keystrokes to action names The name of an action (a String) A component's ActionMap maps keystrokes to action names Action: Contains code to be performed when the keys are pressed 54 jonkv@ida Key Bindings: The Concept 55 Alternative to KeyListener: Key Bindings class MyGameComponent extends JComponent { class MoveLeftAction extends AbstractAction { public void actionPerformed(ActionEvent e) { …do something… } } private void addBindings() { Action moveToTheLeft = new MoveLeftAction(); getActionMap().put(”moveLeft”, moveToTheLeft); } } Define a class implementing Action (in one of many ways…) Create an Action object (can be used in menus or other places as well) Define which Action is called for the action name ”moveLeft” jonkv@ida Key Bindings: ActionMap 56 Alternative to KeyListener: Key Bindings Works if keyboard focus class MyGameComponent extends JComponent { is in THIS component private void addBindings1() { InputMap map1 = getInputMap(JComponent.WHEN_FOCUSED); map1.put(KeyStroke.getKeyStroke(”LEFT”), ”moveLeft”); Check the KeyStroke Javadoc for examples } … https://docs.oracle.com/javase/8/docs/api/javax/swing/KeyStroke.html An action name jonkv@ida Key Bindings: InputMap 57 Alternative to KeyListener: Key Bindings class MyGameComponent extends JComponent { Works if keyboard focus private void addBindings2() { is here or in a subcomponent InputMap map2 = getInputMap( JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); map2.put(KeyStroke.getKeyStroke(”released RIGHT”, ”stopRight”)); Works if keyboard focus is in the same window InputMap map3 = getInputMap( JComponent.WHEN_IN_FOCUSED_WINDOW); map3.put(KeyStroke.getKeyStroke(”Ctrl F2”, ”quit”)); } Fönster Menyrad Meny1 Val1 ContentPane Meny2 Val2 Val3 Panel Knapp1 Knapp2 JScrollPane Textfält Statusrad jonkv@ida Key Bindings: InputMap Standard dialog windows: JOptionPane Simple question: ▪ String input = JOptionPane.showInputDialog("Please input a value"); Can specify a frame that owns the dialog ▪ Blocks input to this frame ▪ JOptionPane.showMessageDialog(frame, "Eggs are not supposed to be green."); Can give additional options ▪ JOptionPane.showMessageDialog(frame, "Eggs are not supposed to be green.", "Inane warning", JOptionPane.WARNING_MESSAGE); 59 jonkv@ida JOptionPane 60 Complex dialog windows ▪ // Custom button text Object[] options = { "Yes, please", "No, thanks", "No eggs, no ham!" }; int optionChosen = JOptionPane.showOptionDialog( frameParent, // A window that “owns” the dialog "Would you like some green eggs to go with that ham?", "A Silly Question", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, // Custom text options[2] // Default choice ) http://docs.oracle.com/javase/tutorial/uiswing/components/dialog.html jonkv@ida JOptionPane (2) 61 Additional dialog windows: File dialogs ▪ http://docs.oracle.com/javase/tutorial/uiswing/components/filechooser.html Color selection dialogs ▪ http://docs.oracle.com/javase/tutorial/uiswing/components/colorchooser.html jonkv@ida File and Color Dialogs To close a window: Call frame.dispose(). Frees all associated resources To configure what the close button does: Use myframe.setDefaultCloseOperation(x), where x is… ▪ WindowConstants.HIDE_ON_CLOSE (default, hides but does not dispose) ▪ WindowConstants.DO_NOTHING_ON_CLOSE ▪ WindowConstants.DISPOSE_ON_CLOSE ▪ WindowConstants.EXIT_ON_CLOSE 63 jonkv@ida Closing Windows 1 64 To add an "are you sure?" dialog: Use DO_NOTHING_ON_CLOSE Add a WindowListener package java.awt.event; public interface WindowListener extends EventListener { public void windowOpened(WindowEvent e); public void windowClosing(WindowEvent e); public void windowClosed(WindowEvent e); public void windowIconified(WindowEvent e); public void windowDeiconified(WindowEvent e); public void windowActivated(WindowEvent e); public void windowDeactivated(WindowEvent e); } Called when the close button is pressed jonkv@ida WindowListener 65 Don't want to implement every method? Extend WindowAdapter package java.awt.event; public class WindowAdapter implements WindowListener { public void windowOpened(WindowEvent e) { } public void windowClosing(WindowEvent e) { } public void windowClosed(WindowEvent e) { } public void windowIconified(WindowEvent e) { } public void windowDeiconified(WindowEvent e) { } public void windowActivated(WindowEvent e) { } public void windowDeactivated(WindowEvent e) { } } Empty implementations of all methods jonkv@ida WindowAdapter 66 Adding an appropriate listener: public class GUIcreator { private class CloseButtonHandler extends WindowAdapter { public void windowClosing(final WindowEvent e) { int answer = JOptionPane.showConfirmDialog (f, "Do you really want to quit?", "Quit?", JOptionPane.YES_NO_OPTION); if (answer == JOptionPane.YES_OPTION) { System.exit(0); } } } public static void addCloseListener(final Frame f) { f.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); f.addWindowListener(new CloseButtonHandler()); } } } jonkv@ida Adding a Dialog 67 An alternative solution (inner class): public class GUIcreator { public static void addCloseListener(final Frame f) { f.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); f.addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(final WindowEvent e) { int answer = JOptionPane.showConfirmDialog (f, "Do you really want to quit?", "Quit?", JOptionPane.YES_NO_OPTION); if (answer == JOptionPane.YES_OPTION) { System.exit(0); } } }); } } jonkv@ida Alternative Solution 69 jonkv@ida Debugging a GUI Program You can view the component hierarchy Select a frame (window) and press Ctrl-Shift-F1 The component hierarchy is dumped to standard error app.TestFrame[frame0,0,0,640x480,layout=java.awt.BorderLayout,resizable,title=,defaul tCloseOperation=HIDE_ON_CLOSE,rootPane=javax.swing.JRootPane[,4,25,632x451,lay out=javax.swing.JRootPane$RootLayout,alignmentX=null,alignmentY=null,border=,flag s=3666,maximumSize=,minimumSize=,preferredSize=],rootPaneCheckingEnabled=true] javax.swing.JRootPane[,4,25,632x451,layout=javax.swing.JRootPane$RootLayout,ali gnmentX=null,alignmentY=null,border=,flags=3666,maximumSize=,minimumSize=,p referredSize=] ▪ … ▪ javax.swing.JPanel[null.contentPane,0,0,632x451,layout=javax.swing.JRootPane $1,alignmentX=null,alignmentY=null,border=,flags=34,maximumSize=,minimu mSize=,preferredSize=,defaultLayout=java.awt.FlowLayout[hgap=5,vgap=5,align =center]] app.TestFrame$DateComponent[,0,0,632x451,alignmentX=null,alignmentY= null,border=,flags=0,maximumSize=,minimumSize=,preferredSize=] Swing: Can replace the look and feel dynamically Nimbus (current Java standard) Metal (earlier Java standard) Windows classic http://docs.oracle.com/javase/tutorial/ uiswing/lookandfeel/ 70 jonkv@ida Pluggable Look and Feel