Wie lässt sich ein Splashscreen mit Fortschrittsanzeige realisieren?
Das Beispiel besteht aus insgesamt drei Klassen:
-
class SplashDemo
-
Erzeugt als GUI einen einfachen, leeren
JFrame
und enthältmain()
. -
class Splash
- Erzeugt das Fenster des Splashscreens
-
class Timer
- Hilfsklasse zur zeitlichen Steuerung des Splashscreens
In den Quelltexten der folgenden Einzeldarstellungen wird aus Gründen der Übersichtlichkeit auf die Angabe der Imports verzichtet. Der ungekürzte Gesamt-Quelltext ist unten zu finden.
public class SplashDemo {
private static final int SHOW_FOR = 3000;
public SplashDemo() {
new Splash("img/rot300x200.png", SHOW_FOR, this);
JFrame frame = new JFrame("Splash-Demo");
frame.setVisible(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 400);
frame.setLocationRelativeTo(null);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new SplashDemo());
}
}
In der von JFrame
abgeleiteten GUI-Klasse der
Anwendung wird ein Objekt vom Typ Splash
erzeugt. Es
liefert das Fensters des Splashscreens und bekommt die folgenden
Parameter übergeben:
- den Pfad zum Splash-Image
- eine Variable, die die Dauer der Darstellung des Splashs enthält
- eine Referenz auf das Hauptfenster, um dies nach Beenden des Splashs sichtbar setzen zu können
Neben dieser Instanzierung werden lediglich die üblichen grundlegenden Eigenschaften eines GUI-Fensters, wie Größe, Beenden des Programms bei Schließen des Fensters, Titel, etc. festgelegt. Wichtig: das Fenster muss unsichbar bleiben, da es erst nach Beenden des Splashs sichbar gesetzt werden soll.
class Splash extends JWindow {
private int min = 0, max = 100;
private boolean show = true;
final JProgressBar progressBar = new JProgressBar(min, max);
public Splash(final String imgPath, final int showFor, final JFrame frame) {
final Timer timer = new Timer(showFor);
Thread wRunner = new Thread() {
public void run() {
timer.start();
while (show && timer.counter <= showFor) {
Splash.this.setVisible(true);
}
Splash.this.setVisible(false);
Splash.this.dispose();
frame.setVisible(true);
}
};
final Runnable pbRunner = new Runnable() {
public void run() {
System.out.println("running progress bar");
for (int i = min; i <= max; i++) {
try {
Thread.sleep(showFor / max);
} catch (InterruptedException e) {
}
progressBar.setValue(i);
}
}
};
JPanel contentPane = new JPanel();
this.setContentPane(contentPane);
contentPane.setLayout(new BorderLayout());
ImageIcon icon = new ImageIcon(ClassLoader.getSystemResource(imgPath));
this.setSize(icon.getIconWidth(), icon.getIconHeight());
contentPane.add(new JLabel(icon, JLabel.CENTER), BorderLayout.CENTER);
contentPane.add(progressBar, BorderLayout.SOUTH);
this.setBackground(Color.WHITE);
this.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
show = false;
setVisible(false);
dispose();
}
});
this.setLocationRelativeTo(null);
this.setVisible(true);
new Thread(wRunner).start();
new Thread(pbRunner).start();
}
}
Die Klasse Splash
ist von JWindow
abgeleitet, einem rahmenlosen 'undecorated' Fenster. In
ihr wird eine Hilfsvariable show
auf true
gesetzt. Sie bestimmt, dass das Fenster des Splashs sichtbar ist.
Zusätzlich wird eine JProgressBar
mit einem
Start- und einem Endwert initialisiert. Im Konstruktor wird als
erstes die zeitliche Steuerung des Splashscreens geregelt. Hierzu
wird ein Objekt der Hilfsklasse Timer
gebildet. Es
bekommt die Dauer der Splash-Darstellung übergeben. In einem
eigenen Thread wird in dessen run()
-Methode
zunächst der Timer gestartet. Solange dessen Zählvariable
counter
kleiner als die Darstellungszeit ist und die
Variable show true
ist bleibt der Splashscreen
sichtbar. Wird eine dieser Bedingungen false
, so
bricht die Darstellung des Splash ab und das Hauptfenster wird
sichtbar.
In einem weiteren Thread wird dann der Fortschritt der
Progressbar ausgeführt. Der Fortschrittsbalken läuft bis
zum Ende der Splash-Darstellung.
Der Rest des Quelltextes umfasst den Aufbau des Splash-Fensters,
das das Image-Objekt auf einem zentral gesetzten JPanel
und im südlichen Borderlayout-Bereich die JProgressBar
darstellt. Um den Splash frühzeitig schließen zu
können, wird das Fenster bei einem MouseListener
angemeldet, über den die Hilfsvariable show
auf false
gesetzt, der Splash abgebrochen und als Folge das Hauptfenster
sichtbar gesetzt wird.
Unmittelbar nach sichtbar setzen des
Splashscreens werden am Ende des Konstruktors die o.a. Threads
gestartet.
class Timer extends Thread {
int counter = 0, showFor;
public Timer(int showFor) {
this.showFor = showFor;
}
public void run() {
while (counter <= showFor) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
counter++;
}
}
}
Die Klasse Timer
ist einfach aufgebaut. Sie ist von Thread
abgeleitet und enthält neben dem Konstruktor lediglich die run()
-Methode,
in der eine Zählvariable bis zum Ablauf der Darstellungsdauer
hochgezählt wird. Ihr aktueller Inhalt wird wie oben
erläutert vom Splashscreen abgefragt.
Nachfolgend der
gesamte Quelltext.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JWindow;
public class SplashDemo {
private static final int SHOW_FOR = 3000;
public SplashDemo() {
JFrame frame = new JFrame("Splash-Demo");
new Splash("img/rot300x200.png", SHOW_FOR, frame);
frame.setVisible(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 400);
frame.setLocationRelativeTo(null);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new SplashDemo());
}
}
class Splash extends JWindow {
private int min = 0, max = 100;
private boolean show = true;
final JProgressBar progressBar = new JProgressBar(min, max);
public Splash(final String imgPath, final int showFor, final JFrame frame) {
this.setBackground(Color.WHITE);
// Mausevent setzt bei Klick die Hilfsvariable show auf false, beendet
// damit den Splashscreen und öffnet das Hauptfenster, sofern es
// geladen ist.
this.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
show = false;
setVisible(false);
dispose();
}
});
// Splash-Hauptsteuerung
final Timer timer = new Timer(showFor);
Thread wRunner = new Thread() {
public void run() {
timer.start();
// Splash zeigen solange er nicht unterbrochen wird (show=false)
// oder das Anzeigeintervall abgelaufen ist.
while (show && timer.counter <= showFor) {
Splash.this.setVisible(true);
}
// Splash beenden
Splash.this.setVisible(false);
Splash.this.dispose();
// Hauptfenster anzeigen
frame.setVisible(true);
}
};
// Progressbar-Thread
final Runnable pbRunner = new Runnable() {
public void run() {
System.out.println("running progress bar");
for (int i = min; i <= max; i++) {
try {
Thread.sleep(showFor / max);
} catch (InterruptedException e) {
}
progressBar.setValue(i);
}
}
};
// Splash-GUI
JPanel contentPane = new JPanel();
this.setContentPane(contentPane);
contentPane.setLayout(new BorderLayout());
ImageIcon icon = new ImageIcon(ClassLoader.getSystemResource(imgPath));
this.setSize(icon.getIconWidth(), icon.getIconHeight());
contentPane.add(new JLabel(icon, JLabel.CENTER), BorderLayout.CENTER);
contentPane.add(progressBar, BorderLayout.SOUTH);
this.setLocationRelativeTo(null);
this.setVisible(true);
new Thread(wRunner).start();
new Thread(pbRunner).start();
}
} // class Splash
class Timer extends Thread {
int counter = 0, showFor;
public Timer(int showFor) {
this.showFor = showFor;
}
public void run() {
System.out.println("timer running");
while (counter <= showFor) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
counter++;
}
}
} // class Timer
Wenn Ihnen javabeginners.de gefällt, freue ich mich über eine Spende an diese gemeinnützigen Organisationen.