Innholdsoversikt for programutvikling
Når et program skal utføre en tidkrevende aktivitet, bør den programmeres i en egen programtråd.
Hvordan dette kan gjøres, er beskrevet i notatet
Multiprosessering.
Det vil dessuten være brukervennlig å indikere at
aktiviteten finner sted, hvor lang tid den ville kunne ta, og hvor mye av den som allerede er utført.
Det kan også være ønskelig at brukeren
får en mulighet til å avbryte aktiviteten. Vi skal etter tur ta for oss tre klasser som kan brukes til
dette formålet. En JProgressBar
er en swing-komponent som indikerer framdrift.
En ProgressMonitor
er en komponent som i utgangspunktet ikke er synlig. Den logger
framdriften av en oppgave og viser en dialogboks med en JProgressBar
i tilfelle
oppgaven tar mer tid enn en grensetid som vi selv kan bestemme. En
ProgressMonitorInputStream
er en input-strøm med en tilknyttet ProgressMonitor
som logger innlesingen fra strømmen. Alle tre klassene blir brukt i kombinasjon med en
SwingWorker
som utfører den tidkrevende aktiviteten ved hjelp av en egen programtråd.
Bruk av SwingWorker
er beskrevet i notatet Multiprosessering nevnt ovenfor, under kapitlet
Oppdatering av brukergrensesnitt under utførelse av tidkrevende kode.
JProgressBar
En JProgressBar
gir et visuelt bilde av framdriften av en oppgave. Bildet nedenfor, som
er hentet fra det etterfølgende programeksempel, viser en slik. En JProgressBar
representerer
en heltallsverdi innenfor et gitt intervall. Når vi oppretter den, kan vi angi minimums- og maksimumsverdier
(det vil si grensene for intervallet):
int min = ...; int max = ...; JProgressBar indikator = new JProgressBar(min, max);
Indikatorens aktuelle verdi blir initialisert til minimumsverdien samtidig med at den blir opprettet. Om vi ikke bestemmer noe annet, vil vi få horisontal visning, som på bildet nedenfor. Vi kan få den vertikal ved å skrive
indikator.setOrientation(SwingConstants.VERTICAL);
Defaultvirkning er at framdriften blir vist ved en farget søyle, som vi ser på figuren. Skal vi i tillegg få prosentangivelse, slik det er vist på figuren, må vi skrive
indikator.setStringPainted(true);
Det er mulig å få vist en alternativ streng istedenfor prosentangivelsen. Følgende bilde viser resultatet av instruksjonen
if (progressBar.getValue() > 900) progressBar.setString("Nesten ferdig");
Instruksjonen ble lagt inn i SwingWorker
-objektets process
-metode.
(Men den er ikke tatt med i programeksemplet nedenfor.)
I enkelte situasjoner har vi ikke noe grunnlag for å finne ut hvor lang tid det kan ta å utføre
en aktivitet. I slike situasjoner kan vi sette en JProgressBar
i ubestemt modus ved å skrive
indikator.setIndeterminate(true);
I programeksemplet nedenfor blir dette gjort når brukeren krysser av i avkryssingsboksen. Det blir da kontinuerlig vist en animasjon som indikerer at det pågår en aktivitet. Følgende bilde viser et øyeblikksbilde fra kjøring av programmet i det følgende eksemplet. Den fargede biten vil bevege seg fram og tilbake innenfor rektanglet som den ligger i.
Følgende program er hentet fra bind to av læreboka Core Java av Cay S. Horstmann og
Gary Cornell. Bildene ovenfor er hentet fra kjøring av programmet.
Programmet simulerer en tidkrevende aktivitet på den måten at en heltallsverdi øker med
én om gangen fra 0 til 1000. Disse grensene brukes som konstruktørparametre på den
JProgressBar
som programmet bruker. For hver økning med én tar den utførende programtråden en pause på 10
millisekunder. Aktiviteten er definert i SwingWorker
-objektets doInBackground
-metode:
104 protected Void doInBackground() throws Exception 105 { 106 try 107 { 108 while (current < target) 109 { 110 Thread.sleep(10); 111 current++; 112 publish(current); 113 } 114 } 115 catch (InterruptedException e) 116 { 117 } 118 return null; 119 }
Legg merke til typeparametrene for det SwingWorker
-objekt som blir definert:
87 class SimulatedActivity extends SwingWorker<Void, Integer>
De to typeparametrene må være klassetyper. Klassen
Void
har ikke annen oppgave
enn å være en klasserepresentasjon av nøkkelordet void
. Det er ikke mulig å opprette
objekter av denne klassetypen. Den brukes her fordi doInBackground
-metoden ikke skal
returnere noen verdi, altså er det vi normalt kaller en
void
-metode. Men i dette
tilfelle må det uttrykkes i form av et klassenavn.
Legg ellers merke til at den simulerte aktivitetens aktuelle verdi, som altså økes fra 0 til 1000 i
løpet av aktiviteten, blir brukt i kallet på publish
, slik at den blir sendt til
process
-metoden. Denne metoden bruker den i sin tur til å oppdatere framdriftsindikatoren ved kall
på dens setValue
-metode.
Veksling mellom bestemt og ubestemt modus for framdriftsindikatoren oppnås ved at avkryssingsboksen er utstyrt med lytteobjekt på følgende måte:
63 checkBox.addActionListener(new ActionListener() 64 { 65 public void actionPerformed(ActionEvent event) 66 { 67 progressBar.setIndeterminate(checkBox.isSelected()); 68 progressBar.setStringPainted(!progressBar.isIndeterminate()); 69 } 70 });
Vi ser at aktuell parameter for setIndeterminate
blir
true
eller
false
avhengig av om det er
krysset av i avkryssingsboksen eller ikke. Denne innstillingen
blir i sin tur brukt til å bestemme om framdriftsindikatoren skal bruke prosentvisning eller ikke.
Fullstendig program er inneholdt i fila
ProgressBarTest.java
som er gjengitt nedenfor.
1 package corejava; 2 3 import java.awt.*; 4 import java.awt.event.*; 5 import java.util.List; 6 import javax.swing.*; 7 8 /** 9 * This program demonstrates the use of a progress bar to monitor 10 * the progress of a thread. 11 * 12 * @version 1.04 2007-08-01 13 * @author Cay Horstmann 14 */ 15 public class ProgressBarTest 16 { 17 public static void main(String[] args) 18 { 19 EventQueue.invokeLater(new Runnable() 20 { 21 public void run() 22 { 23 JFrame frame = new ProgressBarFrame(); 24 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 25 frame.setVisible(true); 26 } 27 }); 28 } 29 } 30 31 /** 32 * A frame that contains a button to launch a simulated activity, 33 * a progress bar, and a text area for the activity output. 34 */ 35 class ProgressBarFrame extends JFrame 36 { 37 private JButton startButton; 38 private JProgressBar progressBar; 39 private JCheckBox checkBox; 40 private JTextArea textArea; 41 private SimulatedActivity activity; 42 public static final int DEFAULT_WIDTH = 400; 43 public static final int DEFAULT_HEIGHT = 200; 44 45 public ProgressBarFrame() 46 { 47 setTitle("ProgressBarTest"); 48 setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); 49 50 // this text area holds the activity output 51 textArea = new JTextArea(); 52 53 // set up panel with button and progress bar 54 final int MAX = 1000; 55 JPanel panel = new JPanel(); 56 startButton = new JButton("Start"); 57 progressBar = new JProgressBar(0, MAX); 58 progressBar.setStringPainted(true); 59 panel.add(startButton); 60 panel.add(progressBar); 61 62 checkBox = new JCheckBox("indeterminate"); 63 checkBox.addActionListener(new ActionListener() 64 { 65 public void actionPerformed(ActionEvent event) 66 { 67 progressBar.setIndeterminate(checkBox.isSelected()); 68 progressBar.setStringPainted(!progressBar.isIndeterminate()); 69 } 70 }); 71 panel.add(checkBox); 72 add(new JScrollPane(textArea), BorderLayout.CENTER); 73 add(panel, BorderLayout.SOUTH); 74 75 // set up the button action 76 startButton.addActionListener(new ActionListener() 77 { 78 public void actionPerformed(ActionEvent event) 79 { 80 startButton.setEnabled(false); 81 activity = new SimulatedActivity(MAX); 82 activity.execute(); 83 } 84 }); 85 } 86 87 class SimulatedActivity extends SwingWorker<Void, Integer> 88 { 89 private int current; 90 private int target; 91 92 /** 93 * Constructs the simulated activity that increments a counter 94 * from 0 to a given target. 97 */ 98 public SimulatedActivity(int t) 99 { 100 current = 0; 101 target = t; 102 } 103 104 protected Void doInBackground() throws Exception 105 { 106 try 107 { 108 while (current < target) 109 { 110 Thread.sleep(10); 111 current++; 112 publish(current); 113 } 114 } 115 catch (InterruptedException e) 116 { 117 } 118 return null; 119 } 120 121 protected void process(List<Integer> chunks) 122 { 123 for (Integer chunk : chunks) 124 { 125 textArea.append(chunk + "\n"); 126 progressBar.setValue(chunk); 127 } 128 } 129 130 protected void done() 131 { 132 startButton.setEnabled(true); 133 } 134 } 135 }
ProgressMonitor
En ProgressMonitor
er en spesiell type dialogboks som inneholder en
JProgressBar
. Dens Cancel-knapp skal kunne brukes til å avbryte aktiviteten,
kombinert med at monitoren da lukker seg.
Følgende bilde viser den som blir brukt i det etterfølgende programeksempel.
Selv om det dreier seg om en dialogboks, er det ikke snakk om en subklasse til JDialog
.
Dens navn starter da heller ikke med bokstaven "J"
, selv om den definerende klassen
tilhører pakken javax.swing
. Klassen
ProgressMonitor
er direkte subklasse til Object
.
For å opprette en monitor finnes det bare følgende
konstruktør:
public ProgressMonitor(Component parentComponent, Object message, String note, int min, int max)
Første parameter er referanse til foreldervinduet. Andre parameter er ment å beskrive den
aktiviteten som blir logget. På bildet ovenfor er det teksten Waiting for Simulated Activity.
Tredje parameter kan brukes til å beskrive aktivitetens tilstand, og den kan endres underveis.
I programeksemplet som bildet ovenfor er hentet fra, er den satt til
null
.
De to siste parametrene bestemmer et intervall. Monitoren oppdaterer seg ikke selv.
Underveis i aktiviteten må det periodisk gjøres kall på metoden
setProgress
til å sette verdier innenfor intervallet [min, max]
. Disse skal indikere hvordan
aktiviteten går framover. (Det er tilsvarende som kall på setValue
-metoden for en
JProgressBar
.)
Monitoren vil lukke seg automatisk når verdien blir satt større enn eller lik
den angitte max
-verdi.
Etter en tid som har default-verdi 500 millisekund, vil monitoren forsøke å beregne hvor lang tid
aktiviteten kan ta. Dersom dette er mer enn 2000 millisekund, vil monitoren dukke opp på skjermen
når det har gått så lang tid. Vi kan endre disse to default-verdiene ved å bruke metodene
setMillisToDecideToPopup
og setMillisToPopup
, men det er sjelden grunn til å
foreta noen endring.
Monitorens Cancel-knapp skal altså kunne brukes til å avbryte den aktiviteten som monitoren
logger. Vi kan imidlertid ikke knytte et lytteobjekt til knappen for å implementere denne funksjonaliteten.
Isteden må vi periodisk gjøre
kall på isCanceled
-metoden for å sjekke om det er blitt klikket på knappen. I det etterfølgende
programeksempel blir det brukt en Timer
til dette formål. Den sørger også for å oppdatere
progresjonen i monitoren.
Programmet ProgressMonitorTest
som er gjengitt nedenfor logger den samme simulerte aktiviteten som forrige programeksempel.
Programmet er stort sett som det ble hentet fra læreboka Core Java, nevnt ovenfor.
Det viste seg at programmet inneholdt en feil som gjorde at aktiviteten ikke ble logget riktig
og stoppet opp lenge før den tid som var tenkt. Dette er rettet opp i det programmet som er gitt
nedenfor. Merk deg følgende:
Timer
-objektet cancelMonitor
blir tilordnet en
ActionListener
i form av en anonym indre klasse, og det blir satt en pause på
500 millisekund mellom hver aktivering av lytteobjektet:
80 cancelMonitor = new Timer(500, new ActionListener() 81 { 82 public void actionPerformed(ActionEvent event) 83 { 84 if (progressDialog.isCanceled()) 85 { 86 activity.cancel(true); 87 startButton.setEnabled(true); 88 } 89 else if (activity.isDone()) 90 { 91 progressDialog.close(); 92 startButton.setEnabled(true); 93 } 94 else 95 { 96 progressDialog.setProgress(activity.getCurrent()); 97 } 98 } 99 });
Lytteobjektet kommuniserer med monitoren progressDialog
. Det sjekker hver gang
om det er klikket på Cancel-knappen, og i så fall så blir den pågående aktiviteten stanset
ved kall på dens cancel
-metode. Dersom aktiviteten er ferdig
(isDone()
), enten fordi den var fullført eller
fordi den er kansellert, blir monitoren lukket. Ellers blir monitoren oppdatert ved kall på dens
setProgress
-metode. Som parameter brukes her aktivitetens aktuelle verdi, som er
programmert til å gå fra 0 til 1000.
(I læreboka som programmet er hentet fra, ble det isteden brukt aktivitetens såkalte
progress
-egenskap. Denne får aldri noen større verdi enn 100.)
Når programmet starter, blir følgende vindu vist:
Start-knappens lytteobjekt er programmert til opprette aktivitet og starte den. Lytteobjektet
oppretter også progresjonsmonitor og starter Timer
-objektet cancelMonitor
.
Disse tingene gjøres ved å utføre følgende kode:
68 activity = new SimulatedActivity(MAX); 69 activity.execute(); 70 71 // launch progress dialog 72 progressDialog = new ProgressMonitor(ProgressMonitorFrame.this, 73 "Waiting for Simulated Activity", null, 0, MAX); 74 cancelMonitor.start();
Den simulerte aktiviteten blir definert av SwingWorker
-klassen
SimulatedActivity
og dens metode doInBackground
:
119 protected Void doInBackground() throws Exception 120 { 121 try 122 { 123 while (current < target) 124 { 125 Thread.sleep(10); 126 current++; 127 textArea.append(current + "\n"); 128 setProgress(100 * current / target); 129 } 130 } 131 catch (InterruptedException e) 132 { 133 } 134 return null; 135 }
Her er kallet på metoden setProgress
endret i forhold til slik som det er gjort
i læreboka som programmet er hentet fra, der det bare brukes current
som aktuell parameter.
Parameteren må nemlig ha verdi mellom 0 og 100. Ellers vil verdien bli avvist ved at metoden kaster ut en
IllegalArgumentException
. I forhold til læreboka er det videre tilføyd en
getCurrent
-metode. Denne behøves for å gi Timer
-objektet riktige verdier for
oppdatering av progresjonen. Legg ellers merke til at i dette programmet er det ikke
SwingWorker
-objektets process
-metode som blir brukt til å oppdatere
progresjonsvisningen. Det er det Timer
-objektet som sørger for.
Fullstendig programkode er som følger:
1 package corejava; 2 3 import java.awt.*; 4 import java.awt.event.*; 5 import javax.swing.*; 6 7 /** 8 * A program to test a progress monitor dialog. 9 * 10 * @version 1.04 2007-08-01 11 * @author Cay Horstmann 12 */ 13 public class ProgressMonitorTest 14 { 15 public static void main(String[] args) 16 { 17 EventQueue.invokeLater(new Runnable() 18 { 19 public void run() 20 { 21 JFrame frame = new ProgressMonitorFrame(); 22 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 23 frame.setVisible(true); 24 } 25 }); 26 } 27 } 28 29 /** 30 * A frame that contains a button to launch a simulated activity 31 * and a text area for the activity output. 32 */ 33 class ProgressMonitorFrame extends JFrame 34 { 35 private Timer cancelMonitor; 36 private JButton startButton; 37 private ProgressMonitor progressDialog; 38 private JTextArea textArea; 39 private SimulatedActivity activity; 40 public static final int DEFAULT_WIDTH = 300; 41 public static final int DEFAULT_HEIGHT = 200; 42 43 public ProgressMonitorFrame() 44 { 45 setTitle("ProgressMonitorTest"); 46 setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); 47 48 // this text area holds the activity output 49 textArea = new JTextArea(); 50 51 // set up a button panel 52 JPanel panel = new JPanel(); 53 startButton = new JButton("Start"); 54 panel.add(startButton); 55 56 add(new JScrollPane(textArea), BorderLayout.CENTER); 57 add(panel, BorderLayout.SOUTH); 58 59 // set up the button action 60 startButton.addActionListener(new ActionListener() 61 { 62 public void actionPerformed(ActionEvent event) 63 { 64 startButton.setEnabled(false); 65 final int MAX = 1000; 66 67 // start activity 68 activity = new SimulatedActivity(MAX); 69 activity.execute(); 70 71 // launch progress dialog 72 progressDialog = new ProgressMonitor(ProgressMonitorFrame.this, 73 "Waiting for Simulated Activity", null, 0, MAX); 74 cancelMonitor.start(); 75 } 76 }); 77 78 // set up the timer action 79 80 cancelMonitor = new Timer(500, new ActionListener() 81 { 82 public void actionPerformed(ActionEvent event) 83 { 84 if (progressDialog.isCanceled()) 85 { 86 activity.cancel(true); 87 startButton.setEnabled(true); 88 } 89 else if (activity.isDone()) 90 { 91 progressDialog.close(); 92 startButton.setEnabled(true); 93 } 94 else 95 { 96 progressDialog.setProgress(activity.getCurrent()); 97 } 98 } 99 }); 100 } 101 102 class SimulatedActivity extends SwingWorker<Void, Integer> 103 { 104 private int current; 105 private int target; 106 107 /** 108 * Constructs the simulated activity that increments a counter 109 * from 0 to a given target. 110 * 111 * @param t the target value of the counter. 112 */ 113 public SimulatedActivity(int t) 114 { 115 current = 0; 116 target = t; 117 } 118 119 protected Void doInBackground() throws Exception 120 { 121 try 122 { 123 while (current < target) 124 { 125 Thread.sleep(10); 126 current++; 127 textArea.append(current + "\n"); 128 setProgress(100 * current / target); 129 } 130 } 131 catch (InterruptedException e) 132 { 133 } 134 return null; 135 } 136 137 public int getCurrent() 138 { 139 return current; 140 } 141 } 142 }
Lesing og skriving av filer ved hjelp av strømmer er beskrevet i notatet
Filbehandling. Der er det blant annet beskrevet hvordan
vi kan sende en strøm gjennom diverse filtre for å omforme den på forskjellige måter.
En filterstrøm som ikke er omtalt i notatet, er
ProgressMonitorInputStream
.
Den kan brukes til å få vist en dialogboks med en progresjonsmonitor som viser framdriften
av innlesingen. Ved innlesing av store filer kan dette være nyttig. (Merk at klassen ligger i pakken
javax.swing
, ikke i java.io
. Det finnes ingen tilsvarende
monitor for skriving til fil.)
For innlesing av tekstfiler har vi brukt en FileReader
:
FileReader leser = new FileReader(f);
der f
kan være et filnavn, en filsti, eller et File
-objekt.
Men dette er bare en alternativ, kortere skrivemåte for følgende kode:
FileInputStream inn = new FileInputStream(f); InputStreamReader leser = new InputStreamReader(inn);
Som det framgår av denne siste koden, er det FileInputStream
som gir basisstrømmen
for input. Filteret av type ProgressMonitorInputStream
må vi plassere mellom
denne basisstrømmen og InputStreamReader
, som konverterer basisstrømmen til en tegnstrøm.
Filteret må dessuten kommunisere med det vinduet som det tilhører. Den nødvendige koden kan vi
dermed skrive på følgende måte:
FileInputStream inn = new FileInputStream(f); ProgressMonitorInputStream monitor = new ProgressMonitorInputStream(forelder, infotekst, inn); InputStreamReader leser = new InputStreamReader(monitor);
Her er det underforstått at forelder
er en referanse til foreldervinduet.
Parameteren infotekst
er ment å skulle gi informasjon om hva det vises progresjon for.
Den kan for eksempel inneholde navn på den fil som blir lest inn.
Som alternativ til å sende den filtrerte strømmen gjennom en InputStreamReader
,
kan vi sende den gjennom en
Scanner
.
Det er gjort i det etterfølgende programeksempel,
der innlesingsstrømmen er opprettet på følgende måte:
104 FileInputStream fileIn = new FileInputStream(f); 105 ProgressMonitorInputStream progressIn = 106 new ProgressMonitorInputStream(this, 107 "Reading " + f.getName(), fileIn); 108 final Scanner in = new Scanner(progressIn);
Her er f
et File
-objekt som representerer vedkommende fil.
Følgende bilde viser et eksempel på hvordan progresjonsmonitoren kan se ut når programmet leser
inn en fil:
Som det blir vist på bildet, inneholder progresjonsmonitoren også en Cancel-knapp. Dersom vil klikker på den, blir innlesingen avbrutt. Vi trenger imidlertid ikke å skrive noe kode for at dette skal skje. Funksjonaliteten er allerede innebygget i dialogboksen som blir vist.
Som alltid når vi skal skrive kode for en tidkrevende oppgave, bør den skrives i en egen programtråd.
Som i de to foregående programeksemplene blir dette også i programeksempel 3
gjort ved at det blir definert en SwingWorker
til å utføre den tidkrevende koden.
Programmet
ProgressMonitorInputStreamTest
som er gjengitt nedenfor, er også hentet fra boka Core Java nevnt foran.
For at en innlesing skal ta såpass lang tid at inputmonitoren blir vist, må fila være litt stor.
En kandidat for innlesing kan være
fila crsto10.txt som er på 2627 kilobyte og inneholder en engelsk
oversettelse av romanen som i norsk oversettelse heter Greven av Monte-Cristo, skrevet av den franske
forfatteren Alexandre Dumas (1802 - 1870). (Det er også laget mange kinofilmer som bygger på romanen, og flere tv-serier,
den siste fra 1998 med
Gérard Depardieu i hovedrollen.)
Legg merke til at når programmet leser inn en fil, så blir hver tekstlinje tilføyd tekstområdet.
Men det foretas ikke noe oppdatering av skjermbildet hver gang dette skjer. På den måten så unngås
flimring under filinnlesing. En annen ting er at dette programmet med hensikt er laget mindre effektivt
enn nødvendig. Det ble gjort for at innlesingen skulle ta såpass lang tid at programmet får vist
progresjonsmonitoren. Mer effektivt ville det vært å bruke en StringBuilder
(se Konstruering av strenger) for å bygge
opp teksten som blir lest inn, og så til slutt sette dens innhold som tekst i tekstområdet når alt er lest inn.
1 package corejava; 2 3 import java.awt.*; 4 import java.awt.event.*; 5 import java.io.*; 6 import java.util.*; 7 import javax.swing.*; 8 9 /** 10 * A program to test a progress monitor input stream. 11 * 12 * @version 1.04 2007-08-01 13 * @author Cay Horstmann 14 */ 15 public class ProgressMonitorInputStreamTest 16 { 17 public static void main(String[] args) 18 { 19 EventQueue.invokeLater(new Runnable() 20 { 21 public void run() 22 { 23 JFrame frame = new TextFrame(); 24 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 25 frame.setVisible(true); 26 } 27 }); 28 } 29 } 30 31 /** 32 * A frame with a menu to load a text file and a text area to display 33 * its contents. The text area is constructed when the file is loaded 34 * and set as the content pane of the frame when the loading is 35 * complete. That avoids flicker during loading. 36 */ 37 class TextFrame extends JFrame 38 { 39 private JMenuItem openItem; 40 private JMenuItem exitItem; 41 private JTextArea textArea; 42 private JFileChooser chooser; 43 public static final int DEFAULT_WIDTH = 300; 44 public static final int DEFAULT_HEIGHT = 200; 45 46 public TextFrame() 47 { 48 setTitle("ProgressMonitorInputStreamTest"); 49 setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); 50 51 textArea = new JTextArea(); 52 add(new JScrollPane(textArea)); 53 54 chooser = new JFileChooser(); 55 chooser.setCurrentDirectory(new File(".")); 56 57 JMenuBar menuBar = new JMenuBar(); 58 setJMenuBar(menuBar); 59 JMenu fileMenu = new JMenu("File"); 60 menuBar.add(fileMenu); 61 openItem = new JMenuItem("Open"); 62 openItem.addActionListener(new ActionListener() 63 { 64 public void actionPerformed(ActionEvent event) 65 { 66 try 67 { 68 openFile(); 69 } 70 catch (IOException exception) 71 { 72 exception.printStackTrace(); 73 } 74 } 75 }); 76 77 fileMenu.add(openItem); 78 exitItem = new JMenuItem("Exit"); 79 exitItem.addActionListener(new ActionListener() 80 { 81 public void actionPerformed(ActionEvent event) 82 { 83 System.exit(0); 84 } 85 }); 86 fileMenu.add(exitItem); 87 } 88 89 /** 90 * Prompts the user to select a file, loads the file into a text 91 * area, and sets it as the content pane of the frame. 92 */ 93 public void openFile() throws IOException 94 { 95 int r = chooser.showOpenDialog(this); 96 if (r != JFileChooser.APPROVE_OPTION) 97 { 98 return; 99 } 100 final File f = chooser.getSelectedFile(); 101 102 // set up stream and reader filter sequence 103 104 FileInputStream fileIn = new FileInputStream(f); 105 ProgressMonitorInputStream progressIn = 106 new ProgressMonitorInputStream(this, 107 "Reading " + f.getName(), fileIn); 108 final Scanner in = new Scanner(progressIn); 109 110 textArea.setText(""); 111 112 SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() 113 { 114 protected Void doInBackground() throws Exception 115 { 116 while (in.hasNextLine()) 117 { 118 String line = in.nextLine(); 119 textArea.append(line); 120 textArea.append("\n"); 121 } 122 in.close(); 123 return null; 124 } 125 }; 126 worker.execute(); 127 } 128 }
Innholdsoversikt for programutvikling
Copyright © Kjetil Grønning, revidert av Eva Hadler Vihovde 2014