Innholdsoversikt for programutvikling
En innvending mot javaprogrammer har vært at de trenger lang tid for å starte opp. Grunnen til at de trenger lang tid er at Javas kjøresystem kan trenge tid til å laste inn alle de nødvendige klassene for et program. Dette kan særlig være tilfelle for swingbaserte vindusprogrammer som kan behøve å hente inn store mengder kode fra klassebiblioteker. Dersom det på skjermen ikke vises noe tegn på at programmet holder på å starte opp, kan brukeren få inntrykk av at det henger, og kan komme til å gjøre gjentatte oppstartforsøk uten å vite noe om første forsøk var vellykket eller ikke. Virkemiddelet mot dette er at det så snart som mulig etter forsøk på programstart kommer opp på skjermen et lite vindu som informerer brukeren om at programmet er i ferd med å starte opp. Et slikt lite vindu kalles på engelsk en splash screen. Jeg kjenner ikke noe godt uttrykk for det på norsk. En mulighet kunne kanskje være oppstartvindu, men da måtte vi i tilfelle ikke blande sammen med startvindu, som er det første "ordentlige" vinduet som programmet viser når det først har rukket å komme skikkelig i gang. I framstillingen nedenfor blir bildet som vises i 'splash screen'-vinduet kalt 'oppstartbilde'.
For at en slik 'splash screen' skal komme opp så fort som mulig, kan
imidlertid ikke visningen av den være avhengig av kode som er initiert av
programmets main
-metode, for main
-metoden blir ikke
satt i gang før all nødvendig programkode og tilhørende biblioteker er lastet inn.
Fra og med javaversjon 6 er dette problemet løst ved at kjøresystemet er gjort
i stand til å vise et bilde umiddelbart etter oppstart. Dette oppstartbildet vises i et vindu
uten såkalte dekorasjoner, det vil si slikt som ramme, ikon og de vanlige knappene
i øverste høyre hjørne. Vi har eksempler på dette ved oppstart av Eclipse og
NetBeans. Bildet under viser det 'splash screen' som kommer opp ved oppstart
av NetBeans.
Det er mulig å bruke et hvilket som helst gif-, jpg- eller png-bilde som oppstartbilde. Det er også mulig å supplere bildene med animasjon (i gif-bilder), og gjennomsiktighet (gif- eller png-bilder). 'Splash screen'-vinduet vil bli vist midt på skjermen. Det blir automatisk lukket så snart det første, ordinære vinduet som tilhører programmet blir vist på skjermen.
Det finnes to mekanismer for å vise 'splash screen' ved oppstart av et program.
Det enkleste alternativet er for oppstart av et program via kommandolinja i et DOS-vindu
ved å bruke opsjonen -splash
ved oppstart.
Dersom class
-fila som inneholder programmets main
-metode
heter MinApplikasjon.class
og bildefila for oppstartbildet heter
splash.gif
og ligger i en katalog bilder
under katalogen
som inneholder nevnte class
-fil, så kan du få startet opp programmet
med tilhørende 'splash screen' på følgende måte:
Åpne et vindu for MS-DOS ledetekst og naviger til den katalogen som inneholder
class
-fila for programmets main
-metode. Dersom den heter
MinApplikasjon.class
, så bruker du følgende DOS-kommando:
java -splash:bilder/splash.gif MinApplikasjon
Java bruker vanlig skråstrek for å angi underkatalog. Det viser seg at i dette tilfelle, iallfall med Windows 7 og Java 7, så går kommandoen greit både med vanlig skråstrek og med bakoverskråstrek.
En vanlig måte å distribuere javaprogrammer på, er imidlertid å pakke dem i jar-filer. Dette er beskrevet i notatet Distribuering av javaprogrammer. Da kan vi pakke inn bildefila for oppstartbildet i jar-fila sammen med de andre filene som hører til programmet. I tillegg må vi i den tilhørende såkalte manifestfil spesifisere filsti for oppstartbildet. Med samme navnebruk som beskrevet ovenfor ved bruk av DOS-kommando, må manifestfila inneholde følgende kodelinjer:
Main-Class: MinApplikasjon SplashScreen-Image: bilder/splash.gif
Ved bruk av NetBeans er det svært lett å få lagt inn det nødvendige i både
jar-fila og manifestfila. Gå fram på samme måte som det er beskrevet i notatet
Distribuering av javaprogrammer når det gjelder
bruk av NetBeans.
Når du har fått satt main
-klasse for prosjektet, kan du
i samme dialogboksen for prosjektets 'Properties' klikke på alternativet
Application slik du kan se at det er gjort på bildet under.
Så bruker du Browse ...-knappen bak tekstfeltet for
Splash Screen: til å navigere deg til den bildefila du vil bruke, og
så velge den slik at filsti kommer opp i tekstfeltet, slik du ser det har
gjort på bildet under.
Dersom programmet er klart til å kjøre så snart kjøresystemet kommer til
main
-metoden, behøver du ikke å gjøre noe annet enn det som er
beskrevet ovenfor når det gjelder bruk av 'splash screen'. Men mange programmer
er bygget opp med en såkalt innpluggingsarkitektur på den måten at en liten programkjerne laster inn
en serie med innpluggingsprogram ved oppstart. Eclipse og NetBeans er typiske eksempler
på dette. I slike tilfeller kan vi på oppstartbildet indikere framdriften
av innlastingen. På bildet for NetBeans som er gjengitt ovenfor kan du se at det
er gjort ved den røde streken under teksten
Loading modules...
nederst i bildet.
Det finnes to muligheter for å få indikert framdrift på en 'splash screen'
etter at programmet er kommet så langt som til main
-metoden.
Det ene alternativet er å tegne direkte på oppstartbildet, det andre er å
bytte ut 'splash screen'-vinduet
med et vindu uten dekorasjoner (lukkeknapp etc.) og som inneholder oppstartbildet
fra 'splash screen'-vinduet i tillegg til en JProgressBar
som viser
framdriften. Bruk av JProgressBar
er beskrevet i notatet
Progresjonsindikatorer.
Vi skal se på et eksempelprogram
som inneholder begge teknikkene. Programmet er hentet fra bind 2 av læreboka
Core Java.
For å tegne direkte på oppstartbildet trenger vi en referanse til
SplashScreen
-objektet
og dets grafikk-kontekst. I tillegg trenger vi 'splash screen'-vinduets dimensjoner:
SplashScreen splash = SplashScreen.getSplashScreen(); Graphics2D g2 = splash.createGraphics(); Rectangle grenser = splash.getBounds();
Vi kan nå, ved hjelp av grafikkobjektet g2
,
utføre hva vi vil av tegneinstruksjoner. Når vi har tegnet, gjør
vi kall på SplashScreen
-objektets update
-metode for
å få oppdatert oppstartbildet med det som sist ble tegnet.
I vårt tilfelle ønsker vi å tegne en progresjonsbar nederst i bildet, slik
det blir vist på bildet nedenfor, der progresjonsbaren er kommet omtrent en
firedel bortover, nederst på bildet. Progresjonsbaren er resultat av følgende
to instruksjoner, hentet fra programmet som er gjengitt i sin helhet lenger nede.
27 g.fillRect(x, y, width * percent / 100, height);
28 splash.update();
Her er width
den totale bredden for progresjonsbaren, lik
bredden for 'splash screen'-vinduet fratrukket bredden for rammekanten på hver side av
progresjonsbaren, mens percent
øker fra 0
til
100
i løpet av en løkkegjennomgang. Uttegningen av progressbaren
utføres av metoden init1
som er den første som blir kalt opp
i programmet som er gjengitt nedenfor.
SplashScreen
-objektet blir opprettet av kjøresystemet og det
finnes bare ett slikt objekt, det er ikke mulig å opprette noe slikt objekt selv.
Dersom det ikke på riktig måte er registrert bildefil for oppstartbilde
på kommandolinje for DOS-kommando, eller registrert i manifestfil og jar-fil
som beskrevet ovenfor, så vil getSplashScreen
-metoden returnere
null
.
Det å tegne direkte på oppstartbildet har sine ulemper. Det er brysomt å måtte
beregne alle pikselposisjonene, og den progresjonsbaren vi får tegnet vil ikke
helt være i samsvar med den virkelige framdriften. For å unngå disse problemene
kan vi, når programmet er kommet til main
-metoden, erstatte det
opprinnelige 'splash screen'-vinduet (som vises før main
-metoden starter)
med et oppfølgingsvindu som har samme størrelse som 'splash screen' og inneholder
dets oppstartbilde, men med en JProgressBar
for framdrift lagt oppå bildet.
I et slikt oppfølgingsvindu kan vi også, om vi vil, legge inn hva vi vil av andre
swing-komponenter. Denne teknikken er programmert inn i metoden init2
i programmet som er gjengitt nedenfor. Metoden blir kalt opp umiddelbart etter at
metoden init1
, beskrevet ovenfor, er ferdig med å tegne progresjonsbar
direkte på oppstartbildet. Skjermbildet som er gjengitt under viser hva som skjer
mens init2
blir utført.
Fullstendig programkode er gjengitt nedenfor og finnes i fila
SplashScreenTest.java
.
Bildefil for oppstartbilde er
splash.png
.
Jar-fil for programmet er
corejavasplash.jar
.
1 import java.awt.*; 2 import java.util.List; 3 import javax.swing.*; 4 5 /** 6 * This program demonstrates the splash screen API. 7 * 8 * @version 1.00 2007-09-21 9 * @author Cay Horstmann 10 */ 11 public class SplashScreenTest 12 { 13 private static SplashScreen splash; 14 private static final int DEFAULT_WIDTH = 300; 15 private static final int DEFAULT_HEIGHT = 300; 16 17 private static void drawOnSplash(int percent) 18 { 19 Rectangle bounds = splash.getBounds(); 20 Graphics2D g = splash.createGraphics(); 21 int height = 20; 22 int x = 2; 23 int y = bounds.height - height - 2; 24 int width = bounds.width - 4; 25 Color brightPurple = new Color(76, 36, 121); 26 g.setColor(brightPurple); 27 g.fillRect(x, y, width * percent / 100, height); 28 splash.update(); 29 } 30 31 /** 32 * This method draws on the splash screen. 33 */ 34 private static void init1() 35 { 36 splash = SplashScreen.getSplashScreen(); 37 if (splash == null) 38 { 39 System.err.println("Did you specify a splash image with " + 40 " -splash or in the manifest?"); 41 System.exit(1); 42 } 43 44 try 45 { 46 for (int i = 0; i <= 100; i++) 47 { 48 drawOnSplash(i); 49 Thread.sleep(100); // simulate startup work 50 } 51 } 52 catch (InterruptedException e) 53 { 54 } 55 } 56 57 /** 58 * This method displays a frame with the same image as the splash screen. 59 */ 60 private static void init2() 61 { 62 final Image img = Toolkit.getDefaultToolkit().getImage(splash.getImageURL()); 63 64 final JFrame splashFrame = new JFrame(); 65 splashFrame.setUndecorated(true); 66 67 final JPanel splashPanel = new JPanel() 68 { 69 public void paintComponent(Graphics g) 70 { 71 g.drawImage(img, 0, 0, null); 72 } 73 }; 74 75 final JProgressBar progressBar = new JProgressBar(); 76 progressBar.setStringPainted(true); 77 splashPanel.setLayout(new BorderLayout()); 78 splashPanel.add(progressBar, BorderLayout.SOUTH); 79 80 splashFrame.add(splashPanel); 81 splashFrame.setBounds(splash.getBounds()); 82 splashFrame.setVisible(true); 83 84 new SwingWorker<Void, Integer>() 85 { 86 protected Void doInBackground() throws Exception 87 { 88 try 89 { 90 for (int i = 0; i <= 100; i++) 91 { 92 publish(i); 93 Thread.sleep(100); 94 } 95 } 96 catch (InterruptedException e) 97 { 98 } 99 return null; 100 } 101 102 protected void process(List<Integer> chunks) 103 { 104 for (Integer chunk : chunks) 105 { 106 progressBar.setString("Loading module " + chunk); 107 progressBar.setValue(chunk); 108 splashPanel.repaint(); // because img is loaded asynchronously 109 } 110 } 111 112 protected void done() 113 { 114 splashFrame.setVisible(false); 115 116 JFrame frame = new JFrame(); 117 frame.setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); 118 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 119 frame.setTitle("SplashScreenTest"); 120 frame.setVisible(true); 121 } 122 }.execute(); 123 } 124 125 public static void main(String args[]) 126 { 127 init1(); 128 129 EventQueue.invokeLater(new Runnable() 130 { 131 public void run() 132 { 133 init2(); 134 } 135 }); 136 } 137 }
Innholdsoversikt for programutvikling
Copyright © Kjetil Grønning, revidert av Eva Hadler Vihovde 2014