Grafische Benutzeroberflächen mit Swing (1)

Werbung
Grafische Benutzeroberflächen
mit Swing
Sven Hartmeier
[email protected]
Übersicht
●
Historisches
–
–
●
●
●
Applet vs. WebStart vs. Application
Sicherheitskonzepte in Java / Sandbox
DesignPattern : MVC
–
●
●
AWT vs. JFC/Swing
leicht- und schwergewichtige Elemente
Beispiel
Swing : Komponenten, Layouts, Ereignisse
Threads
Historisches (1)
●
Java 1.0 (1996)
AWT (AbstractWindowToolkit)
package java.awt.*
●
Java 1.1 (1997)
OO- Ereignissteuerung,
JFC/Swing als Erweiterung
package javax.swing.*
●
seit Java 1.2 (1998)
JFC/Swing als Standard GUI
Historisches (2)
AWT
●
●
●
●
nur wenige Komponenten
Thread-sicher
kein MV Prinzip
HeavyWeight
JFC/Swing
●
●
●
●
●
●
unzählige Komponenten
erweiterbar
nicht Thread-sicher
MV Prinzip
skinable
LightWeight
LightWeight vs. HeavyWeight
●
●
●
●
●
keine direkte Repräsentation im UI
plattformunabhängig
aber : keine plattformspezifischen
Komponenten
Erscheinungsbild kann während der Laufzeit
und unabhängig vom System geändert
werden (skinable)
einfach erweiterbar
Applet, Webstart und
Applikation
Browser
javaws
java
JVM
Sandbox
Applet
WebStart
Application
Designpattern
ModelViewController
Model
View
Controller
Modell
(Model)
●
●
Datenfelder
Logik (Funktionen)
Model
View
Controller
Repräsentation
(View )
●
●
Darstellung des Modells
Benutzerinteraktion
Model
View
Controller
Steuerung
(Controller)
●
●
●
Benutzeraktion auswerten
Aktion ausführen
Präsentation ändern
Model
View
Controller
Ein Fenster zur Welt
import javax.swing.JFrame;
public class HelloSwingFrame {
public static void main(String[] args) {
JFrame f = new JFrame("Das Fenster zur Welt!");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(300,200);
f.setVisible(true);
}
}
Klassenhierachie
Canvas
Canvas
javax.swing.*
Panel
Panel
TextComponent
TextComponent
Component
Component
Container
Container
JTextComponent
JTextComponent
JComponent
JComponent
Button
Button
CheckBox
CheckBox
JPanel
JPanel
AbstractButton
AbstractButton
Window
Window
JWindow
JWindow
Frame
Frame
java.awt.*
JFrame
JFrame
Buttons
JButton
JButton
JToggleButton
JToggleButton
JCheckBox
JCheckBox
JRadioButton
JRadioButton
AbstractButton
AbstractButton
JMenuItem
JMenuItem
JMenu
JMenu
JCheckBoxMenuItem
JCheckBoxMenuItem
JRadioButtonMenuItem
JRadioButtonMenuItem
JButton
import javax.swing.JButton;
import javax.swing.JFrame;
public class Beispiel_JButton {
public static void main(String [] args){
JFrame f = new JFrame("Das Fenster zur Welt!");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new JButton("Ich bin ein JButton!"));
f.setSize(300,200);
f.setVisible(true);
}
}
JTextComponent
JTextComponent
JTextComponent
JTextField
JTextField
JTextArea
JTextArea
JEditorPane
JEditorPane
JTextPane
JTextPane
JFormattedTextField
JFormattedTextField
JPasswordField
JPasswordField
Text Controls
Plain Text Areas
Styled Text Areas
JTextField
import javax.swing.JFrame;
import javax.swing.JTextField;
public class Beispiel_JTextField {
public static void main(String[] args) {
JFrame f = new JFrame("Das Fenster zur Welt!");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new JTextField("Ich bin ein JTexfield!",60));
f.setSize(300,200);
f.setVisible(true);
}
}
JLabel
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Beispiel_JLabel {
public static void main(String[] args) {
JFrame f = new JFrame("Das Fenster zur Welt!");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new JLabel("Ich bin ein JLabel!",60));
f.setSize(300,200);
f.setVisible(true);
}
}
JPanel
●
●
●
Behälter für andere JComponenten
(JPanel, JButton, JTextField, ...)
JPanel zeichnet nur seinen Hintergrund
benutzt einen LayoutManager um
JComponenten im JPanel anzuordnen
typische Anwendung :
Positionieren von JComponenten
Layout : FlowLayout
...
public class Beispiel_FlowLayout extends JPanel{
public Beispiel_FlowLayout(){
for(int i = 1; i <= 5; ++i){
add(new JButton("Button "+(Math.pow(10, i))));
}
}
public static void main(String[] args) {
JFrame f = new JFrame("FlowLayout");
f.add(new Beispiel_FlowLayout());
f.pack();
f.setVisible(true);
}
}
Layout : BorderLayout
...
public class Beispiel_BorderLayout extends JPanel{
public Beispiel_BorderLayout(){
setLayout(new BorderLayout());
add(new JButton("Norden"),BorderLayout.NORTH);
add(new JButton("Westen"),BorderLayout.WEST);
add(new JButton("Osten"),BorderLayout.EAST);
add(new JButton("Süden"),BorderLayout.SOUTH);
add(new JButton("Mitte"),BorderLayout.CENTER);
}
...
Layout : GridLayout
...
public class Beispiel_GridLayout extends JPanel {
public Beispiel_GridLayout(){
setLayout(new GridLayout(3,3));
for (int i = 9; i >= 1; --i){
add(new JButton(new Integer(i).toString()));
}
}
...
Layout : BoxLayout
...
public class Beispiel_BoxLayout extends JPanel {
public Beispiel_BoxLayout(){
this(BoxLayout.X_AXIS);
}
public Beispiel_BoxLayout(int direction){
setLayout(new BoxLayout(this, direction));
for(int i = 1; i <=5; ++i){
add(new JButton(new Integer(i).toString()));
}
}
...
Ereignissteuerung
●
●
●
●
eine Komponente kann ein Ereignis (Event)
auslösen
jedes Event wird durch eine Klasse repräsentiert
(z.B. ActionEvent)
ein Event kann durch ein oder mehrere Listener
verarbeitet werden
JComponents haben ähnliche Methoden zum
Hinzufügen und Entfernen von Listenern für ein
unterstütztes Event
– addXXXListener(XXXEvent)
– removeXXXListener();
Beispiel : Das Interface
ActionListener
import
import
import
import
public
java.awt.event.ActionEvent;
java.awt.event.ActionListener;
javax.swing.JButton;
javax.swing.JFrame;
class BeispielActionListener implements ActionListener {
public void actionPerformed(ActionEvent ae){
//Ausgabe des zum ActionEvent gehörenden ActionEvent
System.out.println(“Geklickt: ”+ae.getActionCommand());
}
public static void main(String[] args){
JFrame jf = new Jframe(“BeispielActionListener”);
//Beschriftung des Jbutton ist gleichzeitig ActionCommand
JButton jb = new JButton(“Klick mich”);
BeispielActionListener bal = new BeispielActionListener();
jb.addActionListener(bal);
jf.setVisible(true);
jf.pack();
}
}
bei Klick
> Geklickt: Klick mich
Events und Listener Typen
●
Es gibt viele weitere, spezialisierte Eventund dazu passende Listener-Typen
Mehr dazu unter:
http://java.sun.com/docs/books/tutorial/uiswing/events/index.html
Was sind Threads?
●
●
●
Erlauben Nebenläufigkeit von
unterschiedlichen Programmteilen
Quasi-parallel, je nach Systemarchitektur
auch echt parallel
Ermöglichen bessere Ausnutzung von
Prozessorzeit und anderen Resourcen, z.B.
Bandbreite einer Internetverbindung
Threads in Java: Die Klasse
java.lang.Thread
public class ThreadDemo extends Thread{
//Diese Methode stammt aus Runnable, ist aber in Thread
//leer implementiert und muss daher überschrieben werden
public void run(){
//Zählen in einer Schleife von 0 bis 9
for(int i=0;i<10;i++){
//Ausgabe jeder Zahl auf der Konsole
System.out.println("Zahl "+i);
}
//fertig!
System.out.println("Fertig!");
}
public static void main(String[] args){
//Erzeugen einer neuen Instanz, inklusive Thread
ThreadDemo td = new ThreadDemo();
//Thread starten
td.start();
}
}
Threads in Java: Das Interface
java.lang.Runnable
public class RunnableDemo implements Runnable{
//Diese Methode stammt aus Runnable und muss
//implementiert werden
public void run(){
//Zählen in einer Schleife von 0 bis 9
for(int i=0;i<10;i++){
//Ausgabe jeder Zahl auf der Konsole
System.out.println("Zahl "+i);
}
//fertig!
System.out.println("Fertig!");
}
public static void main(String[] args){
//Erzeugen einer neuen Instanz
RunnableDemo rd = new RunnableDemo();
//Erzeugen eines Thread, um das Runnable auszuführen
Thread t = new Thread(rd);
//Thread starten
t.start();
}
}
Beispiel: Downloadmanager
●
●
●
●
Wir wollen ein Programm zum Download von
Dateien schreiben
Es sollen mehrere Dateien geladen werden
können
Eingabe: URLs, die die Dateien auf einem
entfernten Rechner addressieren, Zugriff
über das http Protokoll
Öffnen einer Verbindung pro Datei,
herunterladen der Datei auf den lokalen
Rechner
Beispiel: Downloadmanager
public class DownloadManager{
public DownloadManager(URL[] url) {
//Vereinfachte For-Schleife
for(URL u:url){//sequentiell-> Ausführung hintereinander
download(u);
}
}
public File download(URL url) {
//Öffne http Verbindung
HttpURLConnection connection = (HttpURLConnection)
url.openConnection();
//Verbinde mit Server
connection.connect();
//öffne url
InputStream istream = connection.getInputStream();
//lese von istream und schreibe in datei (ohne Details)
return readFile(istream);
}
...
}
Beispiel: Downloadmanager
●
●
●
Problem 1: Wir wollen mehr als eine Datei
gleichzeitig herunterladen können, um
unseren Internetanschluß voll auszulasten
Problem 2: Download einer Datei dauert
eventuell sehr lang, andere sind vielleicht
schneller heruntergeladen
Lösung: Jede Datei wird von einem eigenen,
unabhängigen Thread heruntergeladen!
Beispiel: Downloadmanager
Beispiel: Downloadmanager
public class Download implements Runnable {
private URL url = null;
public Download(URL url) {
this.url = url;
}
public void run() {
HttpURLConnection connection = null;
try {//Verbindung aufbauen
connection = (HttpURLConnection) url.openConnection();
connection.connect();
readFile(connection.getInputStream());//einlesen
} catch (IOException e) {
e.printStackTrace();
} finally {
if (connection != null) {//Verbindunng in jedem Fall schliessen
connection.disconnect();
}
}
...
}
Beispiel: Downloadmanager
public class DownloadManager2{
public DownloadManager2(URL[] url) {
//Vereinfachte For-Schleife (ab Java 1.5)
for(URL u:url){//sequentiell-> Ausführung hintereinander
Thread t = new Thread(new Download(u));
t.start();//Methode kehrt sofort zurück -> Ausführung der
//anderen Downloads beginnt unmittelbar
}
}
public static void main(String[] args) {
URL[] url = new URL[args.length];//Vorsicht, evtl. ist args==null
for(int i=0;i<args.length;i++) {
url[i] = new URL(args[i]);
}
//Download starten
DownloadManager2 dm = new DownloadManager2(url);
}
}
Speziallfall Swing: Der Event
Dispatch Thread
●
●
●
Die meisten Swing Objektmethoden sind
nicht synchronisiert => Veränderungen durch
verschiedene Threads können zu
Inkonsistenzen führen
Daher: Synchronisierungen von Änderungen
über den Event Dispatch Thread => Events
werden dadurch in der Reihenfolge Ihres
Eintreffens ausgeführt
Code auf dem EDT sollte nicht lange
brauchen, sonst => Blockieren der GUI!
ActionListener revisited, wie
man die GUI blockiert
...
public class BeispielActionListener implements ActionListener {
...
public void actionPerformed(ActionEvent ae){
//Ausgabe des zum ActionEvent gehörenden ActionEvent
System.out.println(“Geklickt: ”+ae.getActionCommand());
//eintausend Wiederholungen
for(int i = 0; i< 1000;i++) {
if (SwingUtilities.isEventDispatchThread(){
//Ausführung im EventDispatchThread?
System.out.println("Running on EDT!");
}
try {//Für 100 Millisekunden schlafen
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
...
> Geklickt: Klick
}
bei Klick
und 1000x
> Running on EDT!
mich
Spezialfall Swing: Der Event
Dispatch Thread
//Erweiterung von Download
public class Download implements Runnable {
//Jlabel stellt u.a. einzeilige Strings dar, nicht editierbar!
Jlabel progressLabel = null;
...
public Download(URL url, Jlabel progressLabel) {
this.url = url;
this.progressLabel = progressLabel;
}
@Override
public void run() {
HttpURLConnection connection = null;
try {//Verbindung aufbauen
updateLabel(“Baue Verbindung auf zu “+url.toString());
connection = (HttpURLConnection) url.openConnection();
connection.connect();
updateLabel(“Verbunden”);
readFile(connection.getInputStream());//einlesen
updateLabel(“Datei geladen!”);
...
}
}
Spezialfall Swing: Der Event
Dispatch Thread
//Erweiterung von Download
public class Download implements Runnable {
...
//message ist als final (unveränderlich) deklariert
private void updateLabel(final String message) {
Runnable r = new Runnable(
public void run() {
//Nur Setzen der Nachricht auf dem Jlabel,
//keine zeitintensiven Aktionen!
progressLabel.setText(message);
}
);
//Führt r demnächst auf dem EventDispatch aus
SwingUtilities.invokeLater(r);
}
...
}
Threads: Zusammenfassung
●
●
●
●
Threads sind in Java einfach zu benutzen
Für unabhängige Aufgaben in einer GUI: s.h.
Beispiel MyWorker im Skript
Je unabhängiger ein Programmteil von
Interaktion mit anderen ist, desto einfacher
ist dessen Auslagerung in einen Thread
Mit Threads sind vorhandene Resourcen,
z.B. verfügbare Prozessoren eines Rechners
besser nutzbar
Threads: Zusammenfassung
●
●
●
Offene Probleme: Threads, die sich eine
Resource teilen, z.B. die Standardausgabe
(Konsole), konkurrieren um den Zugriff
darauf => Synchronisierung nötig, sonst nicht
vorhersagbares Verhalten
Nicht behandelt: Der Lebenszyklus eines
Threads
Dazu und zu vielem mehr
http://java.sun.com/docs/books/tutorial/essential/concurrency/
Lesenswertes ...
●
Java ist auch eine Insel – Kapitel 15
http://www.galileocomputing.de/openbook/javainsel7/
●
Swing Tutorial
http://java.sun.com/docs/books/tutorial/uiswing/
Herunterladen