Innholdsoversikt for programutvikling
Programmering av lukkeknappen til et vindu ble omtalt i notatet Vindusbaserte programmer, Programeksempel 1. Vi lærte der at vi for vindusobjektet må utføre instruksjonen
setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
for at programmet skal avslutte når vi klikker på lukkeknappen. (Den forhåndsprogrammerte virkningen er at vinduet bare lukker seg, uten at programmet blir avsluttet.) I noen situasjoner ønsker vi imidlertid at programmet skal virke på den måten at før det blir avsluttet, så skal programmet lagre på fil de data det har brukt. For å få til dette, er det nødvendig å foreta en mer omfattende programmering av lukkeknappen. Vi skal nå gjøre det nødvendige forarbeidet til dette, eksempler på at det virkelig blir foretatt lagring på fil i forbindelse med bruk av lukkeknappen får vi ikke tatt før vi har lært om filbehandling. For et eksempel på dette, se programeksemplet under Serialisering av objekter i notatet Filbehandling.
Når vi klikker på lukkeknappen til et vindu, blir det generert en hendelse
av type WindowEvent
. Denne kan vi fange opp ved at vi definerer
og oppretter et lytteobjekt av type WindowListener
, samt
registrerer dette objektet som lytteobjekt for vinduet vårt ved å bruke
det som parameter i et kall på metoden
addWindowListener
. Når vi klikker
på lukkeknappen, vil det da bli gjort kall på lytteobjektets metode
windowClosing
. Det er derfor i denne vi må legge inn de
instruksjonene vi ønsker utført når det blir klikket på lukkeknappen.
Instruksjonen for normal programavslutning er
System.exit( 0 );
Parameteren til metodekallet er en statuskode. En verdi forskjellig fra null signaliserer unormal programavslutning.
Det vi ønsker utført av andre instruksjoner i forbindelse med programavslutning, for eksempel lagring av data på fil, må plasseres før denne avslutningsinstruksjonen.
Interface
WindowListener
inneholder i tillegg til
windowClosing
seks andre metoder. I enkle programmer er det ikke
nødvendig å putte noen instruksjoner inni dem. For at vi i definisjonen av
vårt lytteobjekt skal slippe å skrive opp alle disse metodene med tomt innhold,
er det i javas klassebibliotek definert en klasse
WindowAdapter
.
Denne implementerer
interface WindowListener
, men gir alle de sju metodene tomt
innhold. For å definere lytteobjekt kan vi derfor, istedenfor å definere en
klasse som implementerer interface WindowListener
, definere en
subklasse til WindowAdapter
der vi redefinerer metoden
windowClosing
. Denne framgangsmåten skal vi bruke i følgende eksempel der vi
omprogrammerer vinduet til et tidligere programeksempel, slik at det til
vinduets lukkeknapp blir knyttet et lytteobjekt som kan brukes til programavslutning.
Som eksempel på det opplegget som er skissert ovenfor, skal vi omarbeide
programmet for bokliste som er brukt som eksempel på
Datatype for sammenkjedet liste i notatet
om datastrukturer. Det ble der definert et vindu
Bokhylle
. Programmets klasser
Bok
og
Bokliste
kan vi bruke uendret. I vindusklassen Bokhylle
legger vi inn en
indre klasse som definerer vinduslytter. Denne klassen ser ut slik:
private class Vinduslytter extends WindowAdapter { public void windowClosing( WindowEvent e ) { System.exit( 0 ); } }
I vindusklassens konstruktør registrerer vi en vinduslytter for vinduet ved følgende instruksjon:
addWindowListener( new Vinduslytter() );
Du kan hente fullstendig kildekode for den reviderte vindusklassen fra
følgende link:
Bokhylle2.java
.
I programmets main
-metode, som finnes i klassen
Boksamling2
gjør vi ikke noe annet enn å opprette et vindusobjekt av den definerte typen:
public class Boksamling2 { public static void main( String[] args ) { Bokhylle2 hylle = new Bokhylle2(); } }
Opprett for deg selv et program med de nye klassene Bokhylle2
og
Boksamling2
og sjekk at både program og lukkeknapp virker riktig!
I forrige programeksempel definerer den indre klassen
Vinduslytter
et lytteobjekt for programvinduets lukkeknapp.
Klassen er subklasse til WindowAdapter
.
Vi trenger navnet på klassen bare én gang: Når vi i vindusklassens
konstruktør registrerer et lytteobjekt ved å skrive
addWindowListener( new Vinduslytter() );
I slike tilfeller tillater java at vi lar være å gi klassen et navn. Vi kunne derfor isteden ha skrevet
addWindowListener( new WindowAdapter() { public void windowClosing( WindowEvent e ) { System.exit( 0 ); } } );
Dette resulterer imidlertid i ganske kryptisk kode. Vi må oppfatte det slik
at vi oppretter et objekt av en klasse som er subklasse til klassen
WindowAdapter
, men vi lar være å gi subklassen noe navn.
Istedenfor å ha metodekallet som er vist ovenfor stående inne i konstruktøren
til klassen som definerer programvinduet, kan vi flytte det til
main
-metoden der vindusobjektet blir opprettet. Vi bruker da
vindusobjektet til å foreta metodekallet. På denne måten blir det gjort i den
versjonen av programmet som står nedenfor. Det er bare vindusklassen og applikasjonsklassen
som må endres. De nye filene
Bokhylle3.java
og
Boksamling3.java
er
gjengitt nedenfor. I den siste fila blir det nå nødvendig å importere
pakken java.awt.event
.
1 //Test av enkel bokliste. 2 import java.awt.*; 3 import java.awt.event.*; 4 import javax.swing.*; 5 6 public class Bokhylle3 extends JFrame 7 { 8 private Bokliste bøkene; 9 private JTextField tittel; 10 private JButton skrivUt; 11 private JTextArea utskrift; 12 private Kommandolytter lytter; 13 14 public Bokhylle3() 15 { 16 super( "Test av bokliste" ); 17 bøkene = new Bokliste(); 18 Container c = getContentPane(); 19 c.setLayout( new FlowLayout() ); 20 c.add( new JLabel( "Ny boktittel: " ) ); 21 tittel = new JTextField( 25 ); 22 c.add( tittel ); 23 skrivUt = new JButton( "Skriv bokliste" ); 24 c.add( skrivUt ); 25 utskrift = new JTextArea( 10, 30 ); 26 utskrift.setEditable( false ); 27 c.add( new JScrollPane( utskrift ) ); 28 lytter = new Kommandolytter(); 29 tittel.addActionListener( lytter ); 30 skrivUt.addActionListener( lytter ); 31 } 32 33 public void settInnBok() 34 { 35 Bok ny = new Bok( tittel.getText() ); 36 bøkene.settInn( ny ); 37 tittel.setText( "" ); 38 } 39 40 public void skrivBokliste() 41 { 42 utskrift.setText( bøkene.toString() ); 43 } 44 45 private class Kommandolytter implements ActionListener 46 { 47 public void actionPerformed( ActionEvent e ) 48 { 49 if ( e.getSource() == tittel ) 50 settInnBok(); 51 else if ( e.getSource() == skrivUt ) 52 skrivBokliste(); 53 } 54 } 55 } 1 import java.awt.event.*; 2 3 public class Boksamling3 4 { 5 public static void main( String[] args ) 6 { 7 Bokhylle3 hylle = new Bokhylle3(); 8 hylle.setSize( 400, 300 ); 9 hylle.addWindowListener( 10 new WindowAdapter() { 11 public void windowClosing( WindowEvent e ) 12 { 13 System.exit( 0 ); 14 } 15 } ); 16 hylle.setVisible( true ); 17 } 18 }
Sjekk for deg selv at programmet virker riktig også med de nye klassene!
Når du definerer et programvindu for et applikasjonsprogram, slik vi har gjort i de siste eksemplene, bør du alltid programmere vinduets lukkeknapp slik at den gir programavslutning, for dette er en funksjonalitet som en bruker vil forvente at programmet har. De to måtene å gjøre det på som er vist i de to siste eksemplene må imidlertid bare oppfattes som likeverdige alternativer. Det er ikke slik å forstå at det å bruke anonyme indre klasser er "bedre" enn å bruke navngitte klasser. Tvert imot resulterer anonyme klasser i ganske kryptisk kode. Du bør derfor være svært tilbakeholden med å bruke slike klasser.
Når det gjelder programmering av lukkeknappen til et vindu, vil begge de to alternativene som er beskrevet ovenfor være litt omstendelige for bare å få oppfylt den ene tingen at programmet blir avsluttet når brukeren klikker på lukkeknappen. I slike tilfelle er det enklere å bruke instruksjonen
setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
for vinduet vårt, som er nevnt i begynnelsen av dette notatet.
Til JFrame
-metoden setDefaultCloseOperation
finnes det for øvrig flere valg av aktuell parameter. En av følgende konstanter
kan brukes:
JFrame.EXIT_ON_CLOSE
System.exit(0)
)WindowConstants.DISPOSE_ON_CLOSE
WindowConstants.HIDE_ON_CLOSE
WindowConstants.DO_NOTHING_ON_CLOSE
WindowListener
isteden.)Dersom en for eksempel ønsker at programmet skal lagre data på fil før det
blir avsluttet, er en nødt til å definere en WindowListener
.
(Hvordan en får lagret data på fil er beskrevet i notatet
Filbehandling.)
Videre er det slik at dersom det for vinduet vårt er registrert en
WindowListener
, så vil denne bli aktivert før
behandlingen av lukkehendelsen definert av konstantene ovenfor.
Innholdsoversikt for programutvikling
Copyright © Kjetil Grønning og Eva Hadler Vihovde, revidert 2015