Innholdsoversikt for programutvikling

Progresjonsindikatorer

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.

Bruk av 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.

Programeksempel 1

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 }

Bruk av 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.

Programeksempel 2

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 }

Vise progresjon for en input-strøm

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.

Programeksempel 3

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