Grafische Benutzeroberflächen mit Swing Nils Hoffmann hoffmann@cebitec.uni-bielefeld.de Jan Krüger jkrueger@techfak.uni-bielefeld.de
Organisatorisches Freitags , 6.6.2008 (12 – 14 Uhr) in H7 1. Teil Überblick über Java/Swing Designpattern : MVC 2. Teil Ereignissteuerung in Java/Swing Einführung in Threads Dienstags, 10.6.2008 (12 – 14 Uhr) GZI (V2- 222, V2-229 und V2-234) Übung : ein Taschenrechner mit JFC/Swing richtet sich an Java/JFC/Swing Einsteiger V2-221 V2-240 V2-229
Übersicht Historisches AWT vs. JFC/Swing leicht- und schwergewichtige Elemente Applet vs. WebStart vs. Application Sicherheitskonzepte in Java / Sandbox DesignPattern : MVC 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 JFC/Swing nur wenige Komponenten Thread-sicher kein MV Prinzip HeavyWeight 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 Live Demo zur Veranschaulichung RNAMovies als Beispiel fuer eine Applikation die sowohl Applet, Applikation als auch Webstartapplikation ist http://bibiserv.techfak.uni-bielefeld.de/rnamovies Unterschiede erklaeren Sandbox Applet WebStart Application
Designpattern ModelViewController verschiedene Darstellungen verschiedene aber teilweise doch aehnliche Steuerung gleiches (aehnliches) Datenmodell
Modell (Model) Datenfelder Logik (Funktionen) Model View Controller Modell (model) enthält die abzubildenen Daten und i.d.R. die Geschäftslogik Geschäftslogik entspr. den (Objekt-)Funktionen/Methoden Fragen : Welche Daten muss mein Modell beinhalten ? Was will ich modellieren ? Welche Funktionen brauche ich um die Daten des Modells zu manipulieren ? An der Tafel (Beispiel Taschenrechner) : Welchen Daten braucht ein Taschenrechner ? Operand1, Operand2, Operator, Ergebnis Welche Methoden braucht ein Taschenrechner ? berechne(), setOperand1, setOperand2, setOperator, getErgebnis() View Controller
Repräsentation (View ) Darstellung des Modells Benutzerinteraktion Model Darstellung der Daten Entgegennahme von Benutzeraktionen Aber : Keine Verarbeitung der Ereignisse View Controller
Steuerung (Controller) Benutzeraktion auswerten Aktion ausführen Präsentation ändern Model verwaltet die Präsentation nimmt von der Präsentation Ereignisse entgegen, wertet diese aus und agiert entsprechend “Kennt” Modell und Repräsentation 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 javax.swing.* java.awt.* Canvas Panel TextComponent JTextComponent Component Container JComponent JPanel Button AbstractButton CheckBox Window JWindow Frame JFrame java.awt.*
Buttons JButton JToggleButton JCheckBox AbstractButton JRadioButton JMenuItem JMenu JCheckBoxMenuItem 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 Text Controls Plain Text Areas Styled Text Areas JTextArea JEditorPane JTextField JTextPane JFormattedTextField JPasswordField
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 java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; public 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 Event- und 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 mich und 1000x > Running on EDT! bei Klick
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/