Steuerungstasten

nächste Folie (auch Enter oder Spacebar).
vorherige Folie
 d  schaltet das Zeichnen auf Folien ein/aus
 p  wechselt zwischen Druck- und Präsentationsansicht
CTRL  +  vergrößert die Folien
CTRL  -  verkleinert die Folien
CTRL  0  setzt die Größenänderung zurück

Das Weiterschalten der Folien kann ebenfalls durch das Klicken auf den rechten bzw. linken Folienrand erfolgen.

Java Foundation Classes (JFC)

  • In diesem Kapitel sollen die Java Foundation Classes (JFC) verwendet werden, um plattformunabhängige Desktop-Anwendungen zu erstellen.
  • Die Java Foundation Classes bestehen aus:
    APIFunktion
    Abstract Window Toolkit (AWT)Basisklassen für GUI-Komponenten, Events und Layouts
    SwingGUI-Komponenten, veränderbarer Look-and-Feel
    Java 2DZeichnen von 2D-Elementen
    Java AccessibilityUnterstützungstechnologien z.B. für Mensch mit Sehbehinderung
    Data TransferCut-and-Paste, Drag-and-Drop

Java installieren, kompilieren und ausführen

  • Installation des Java SE Development Kits (Download)
  • Kompilieren: (In einer Shell)
    javac sourcefile.java
  • Ausführen:
    java sourcefile

Das erste GUI

Das erste GUI

  • Verwendet die Komponente JFrame als Top-Level-Container
  • Darstellung des Textes mittels JLabel
gui1


Quelltext des Beispiels: HelloGUI.java

Das erste GUI

import javax.swing.*;

class MyGui extends JFrame { // Klasse mit eigenen GUI Komponenten
  ...
}

public class HelloGUI {
  public static void main(String[] args) {
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        MyGui myGUI = new MyGui(); // Instanzierung der eigenen Klasse
        myGUI.createGUI();         // im Event Dispatching Thread 
      }
    });
  }
}

Das erste GUI

import javax.swing.*;

class MyGui extends JFrame {
  public void createGUI() {
    setTitle("HelloGUI");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setSize(320, 240);
    JLabel label = new JLabel("Hello World");
    getContentPane().add(label);
    setVisible(true);
  }
}

public class HelloGUI {
  ...
}

Hinzufügen eines Menüs

  • Erstellen eines Menüs mit JMenuBar, JMenu und JMenuItem
gui1


Quelltext des Beispiels: MyMenuBar.java

Hinzufügen eines Menüs

class MyGui extends JFrame {
  public void createGUI() {
    ...
    JMenuBar menuBar = new JMenuBar();
    JMenu menu = new JMenu("File");
    menuBar.add(menu);
    JMenuItem item = new JMenuItem("Open");
    menu.add(item);
    setJMenuBar(menuBar);

    setVisible(true);
  }
}

Hinzufügen eines Buttons

  • Erstellen einer Schaltfäche mit JButton
gui1


Quelltext des Beispiels: MyButton.java

Hinzufügen eines Buttons

class MyGui extends JFrame {
  public void createGUI() {
    ...
    setLayout(null); // keine automatisches Layout
   
    JLabel label = new JLabel("Hello World");
    label.setBounds(120, 0, 150, 30); // manuelles Positionieren
    getContentPane().add(label);
    
    JButton button = new JButton("Button Text");
    button.setBounds(120, 30, 150, 30);
    getContentPane().add(button);
    ...
  }
}

Kompositionshierarchie für das Beispiel ("ist Teil von")

containment_hierarchy


gui1

Vererbungshierarchie ("ist ein")

class_hierarchy

Ereignisverarbeitung

Ereignisverarbeitung

  • Ereignisse (Event): Etwas wurde aktiviert, verändert, bewegt, etc.
  • Ereignisquelle: Die Komponente, die von dem Ereignis direkt betroffen ist, z.B. ein gedrückter AbstractButton
  • Ereignisbeobachter (EventListener): Die Klasse, die von dem Ereignis informiert werden möchte
  • Ein Ereignisbeobachter muss sich bei einer Ereignisquelle registrieren, wenn es über dessen Ereignis(se) informiert werden möchte
  • Der Event Dispatching Thread (EDT) läuft im Hintergrund und arbeitet die Ereignisse aller Ereignisquellen nacheinander ab.

Vererbungshierarchie: Event

event_class_hierarchy

Beispiel: ActionEvent

public class ActionEvent extends AWTEvent
{

  // constructors
  public ActionEvent(Object source, int id, String command) { ... }
  ...
  // public members
  public String getActionCommand() { ... } 
  public long getWhen() { ... } 
  public int getModifiers() { ... } 
  public String paramString() { ... }
}

Interface-Hierarchie: EventListener

event_class_hierarchy

Ereignisquelle und Ereignisbeobachter

Beispiel für Ereignisbeobachter: ActionListener
public interface ActionListener extends EventListener {
  void actionPerformed(ActionEvent event);
}

Beispiel für Ereignisquelle: AbstractButton
public abstract class AbstractButton extends ... {
  ...
  public void addActionListener(ActionListener l) {... }
  public void removeActionListener(ActionListener l) {... }
  public ActionListener[] getActionListeners() {... }
  ...
}

Hinzufügen einer Ereignisverarbeitung für den Button

  • Ein Klick auf den Button erhöht einen Zähler und gibt den Zählerstand in einem Label-Text aus
gui1


Quelltext des Beispiels: ActionButton

Hinzufügen einer Ereignisverarbeitung für den Button

class MyGui extends JFrame implements ActionListener{

  private int counter = 0;
  JLabel label = new JLabel("Hello World");
  
  public void createGUI() {
    ...
    JButton button = new JButton("Increment");
    button.addActionListener(this);
    getContentPane().add(button);
    ...
  }
  public void actionPerformed(ActionEvent event) {
    counter++;
    label.setText("Click #" + Integer.toString(counter));
  }
}

Hinzufügen einer Ereignisverarbeitung für das Menü

  • Die Auswahl des MenuItem "Reset" setzt den Zähler zurück
gui_action_menu


Quelltext des Beispiels: ActionMenu.java

Hinzufügen einer Ereignisverarbeitung für das Menü

class MyGui extends JFrame implements ActionListener{
    ...
    JMenuItem item2 = new JMenuItem("Reset", KeyEvent.VK_R);
    item2.addActionListener(this);
    item2.setActionCommand("ResetCmd");
    menu.add(item2);
    setJMenuBar(menuBar);
    ...
  }
  
  public void actionPerformed(ActionEvent event) {
    counter++;
    if(event.getActionCommand().equals("ResetCmd") ) counter = 0;
    label.setText("Click #" + Integer.toString(counter));
  }

MouseEvent und MouseListener

public class MouseEvent extends InputEvent {
  ... 
  public int getX() {...}
  public int getY() {...}
  public Point getPoint() {...}
  public int getButton() {...}
  public String paramString() {...}
  ...
}
public interface MouseListener extends EventListener {
  void mouseClicked(MouseEvent event);
  void mousePressed(MouseEvent event);
  void mouseReleased(MouseEvent event);
  void mouseEntered(MouseEvent event);
  void mouseExited(MouseEvent event);
}

MouseEvent Beispiel

  • Beim Klick mit der Maus auf den JFrame wird die Position des Mauszeigers ausgegeben
gui_mouselistener


Quelltext des Beispiels: MyMouseListener.java

MouseEvent Beispiel

class MyGuiMouseListener implements MouseListener {
  ...
}

class MyGui extends JFrame {
  public void createGUI() {
    ...
    JLabel label = new JLabel("Position: 0, 0");
    label.setBounds(120, 0, 150, 30);
    getContentPane().add(label);
    
    MyGuiMouseListener mouseListener = new MyGuiMouseListener();
    mouseListener.setLabelRef(label);
    addMouseListener(mouseListener);
    ...
  }
}

MouseEvent Beispiel

class MyGuiMouseListener implements MouseListener {
  private JLabel labelRef;
  public void setLabelRef(JLabel label) { labelRef= label; }
  
  public void mousePressed(MouseEvent event) {
    labelRef.setText("Position: " + Integer.toString(event.getX()) +
                     ", " + Integer.toString(event.getY()));
  }
  public void mouseClicked(MouseEvent event) {}
  public void mouseReleased(MouseEvent event){}
  public void mouseEntered(MouseEvent event) {}
  public void mouseExited(MouseEvent event) {}
}

Adapterklassen

  • Wie im vorherigen Beispiel gesehen, müssen beim Implementieren eines EventListener-Interface (wie z.B. MouseListener) alle Methoden vorhanden sein, auch wenn diese nicht benötigt werden
  • Adapterklassen implementieren leere Methoden, sodass nur die benötigten Methoden in einer abgeleiteten Klasse implementiert werden müssen

MouseEvent Verarbeitung mit Adapterklassen

class MyGuiMouseAdapter extends MouseAdapter {
  private JLabel labelRef;
  public void setLabelRef(JLabel label) { labelRef= label; }
  public void mousePressed(MouseEvent event) {
    labelRef.setText("Position: " + Integer.toString(event.getX()) +
                     ", " + Integer.toString(event.getY()));
  }
}

class MyGui extends JFrame {
  public void createGUI() {
    ...
    MyGuiMouseAdapter mouseAdapter = new MyGuiMouseAdapter();
    mouseAdapter.setLabelRef(label);
    addMouseListener(mouseAdapter);
  }
}

Layout-Manager

Layout-Manager

  • In den bisherigen Beispielen wurde kein Layout-Manager verwendet
  • Das ist kein Problem, solange die Fenstergröße nicht verändert wird
class MyGui extends JFrame {
  public void createGUI() {
    ...
    setLayout(null); // keine automatisches Layout
    setResizeable(false); // Fenstergröße ist nicht veränderbar
    
    JLabel label = new JLabel("Hello World");
    label.setBounds(120, 0, 150, 30); // manuelles Positionieren
    getContentPane().add(label);
  }
}

Layout-Manager

  • Ein Layout-Manager automatisiert das Platzieren von Komponenten
  • Das Layout wird automatisch angepasst, wenn sich die Fenstergröße verändert
  • Dazu teilen die einzelnen Komponenten ihre minimale, maximale, und gewünschte Größe mit

LayoutManager Interface

public interface LayoutManager {
  void addLayoutComponent(String name, Component component);
  void removeLayoutComponent(Component component);
  Dimension preferredLayoutSize(Container parent);
  Dimension minimumLayoutSize(Container parent);
  void layoutContainer(Container parent);
} 

Hierarchie LayoutManager

class_hierarchy

Layout-Manager: BorderLayout

  • Der BorderLayout-Manager ist der voreingestellte Standard für viele Fenster, wie z.B. JFrame
  • Das Layout unterteilt das Fenster in 5 Bereiche: Norden, Osten, Süden, Westen und Zentrum
gui_borderlayout

Quelltext des Beispiels: MyBorderLayout.java

Layout-Manager: BorderLayout

class MyGui extends JFrame{
  public void createGUI() {
    ...
    Container contentPane = getContentPane();
    contentPane.setLayout(new BorderLayout(0,0));
    contentPane.add(BorderLayout.NORTH, new JButton("North"));
    contentPane.add(BorderLayout.EAST, new JButton("East"));
    contentPane.add(BorderLayout.SOUTH, new JButton("South"));
    contentPane.add(BorderLayout.WEST, new JButton("West"));
    contentPane.add(BorderLayout.CENTER, new JButton("Center"));
    
    setVisible(true);
  }
}

Layout-Manager: GridLayout

  • Der GridLayout-Manager ordnet die Komponenten auf einem regulären Gitter an
  • Die Komponenten versuchen, ihre zugewiesene Gitterzelle zu füllen
gui_Gridlayout


Quelltext des Beispiels: MyGridLayout.java

Layout-Manager: GridLayout

class MyGui extends JFrame{
  public void createGUI() {
    ...
    Container contentPane = getContentPane();
    // 3 Zeilen mit Abstand 15, und 2 Spalten mit Abstand 5
    contentPane.setLayout(new GridLayout(3, 2, 5, 15));
    contentPane.add(new JButton("Button 1"));
    contentPane.add(new JButton("Button 2"));
    contentPane.add(new JButton("Button 3"));
    contentPane.add(new JButton("Button 4"));
    contentPane.add(new JButton("Button 5"));
    contentPane.add(new JButton("Button 6"));
    
    setVisible(true);
  }
}

Layout-Manager: SpringLayout

  • Der SpringLayout-Manager ist relativ kompliziert zu handhaben und ist eigentlich für die Verwendung mit visuellen GUI-Editoren konzipiert
  • Er ist eine gute Wahl, wenn es z.B. um die Erstellung eines Formulars geht


Quelltext des Beispiels:
MySpringLayout.java, SpringUtilities.java

Layout-Manager: SpringLayout

public void createGUI() { ...
  String[] labels = {"Firstname: ", "Lastname: ", 
                     "Student ID: ", "Enrolled since: "};
  Container cp = getContentPane();
  cp.setLayout(new SpringLayout());
  for (int i = 0; i < labels.length; i++) {
    JLabel label = new JLabel(labels[i], JLabel.TRAILING);
    cp.add(label);
    JTextField textField = new JTextField(10);
    label.setLabelFor(textField);
    cp.add(textField);
  }
  SpringUtilities.makeCompactGrid(cp, labels.length, 2, 5, 5, 5, 5);
  pack(); // dense packing
  setVisible(true);
}

Threads

Beispiel: Lange Berechnungen im eigenen Thread

  • Ein JButton startet eine lange Berechnung
  • Der Fortschritt wird mit einer JProgressBar angezeigt
  • Der Benutzer kann die Berechnung jederzeit abbrechen

gui_action_menu

Quelltext des Beispiels: MyProgressBar.java

Beispiel: Lange Berechnungen im eigenen Thread

class MyGui extends JFrame implements ActionListener {
  final JProgressBar progressBar = new JProgressBar(0, 100);
  final JButton button = new JButton("Compute");
  boolean userStopped = false, threadAlive = false;
  int percent;
  Runnable updateUI = new Runnable() { ... }; // for UI update
  Runnable workerThread = new Runnable() { ... }; // for computation
  
  public void createGUI() {... }
  public void actionPerformed(ActionEvent event) { // button pressed
    if(!threadAlive) {
      threadAlive = true; userStopped = false;
      new Thread(workerThread).start(); 
    } 
    else userStopped = true;
  }
}

Beispiel: Lange Berechnungen im eigenen Thread

  Runnable workerThread = new Runnable() { // for computation

    public void run() {
      for (int i=0; i < 100 && !userStopped; i++) {
        try {
          Thread.sleep(50); // compute something here
          percent = i;
          // run updateUI in the Event Dispatching Thread
          SwingUtilities.invokeLater(updateUI); 
        } catch (InterruptedException e) {}
      }
      percent = 100;
      SwingUtilities.invokeLater(updateUI);
      threadAlive = false;
    }
  };

Beispiel: Lange Berechnungen im eigenen Thread

  Runnable updateUI = new Runnable() { // for UI update

    public void run() {
      if(percent < 100) {
        progressBar.setString("Computing " + percent + "%");
        button.setText("Stop");
      }else{
        progressBar.setString("Done");
        button.setText("Compute");
      }
      progressBar.setValue(percent);
    }
  };

Java 2D

Java 2D

  • Java 2D eignet sich zum Erstellen 2D dimensionaler Zeichnungen
  • Dabei wird die grafische Ausgabe einer AWT-Komponente (wie z.B. JFrame) modifiziert, indem deren paint() Methode überschrieben wird

Beispiel: Linie, Rechteck und Kreis

  • Das Beispiel zeichnet eine Linie, ein Rechteck und einen Kreis

gui_linerectcircle

Quelltext des Beispiels: LineRectCircle.java

Beispiel: Linie, Rechteck und Kreis

class MyGui extends JFrame {
  public void createGUI() {...}

  public void paint(Graphics g) {
    super.paint(g);
    Graphics2D g2d = (Graphics2D) g; // cast to Graphics2D
    Line2D.Double line = new Line2D.Double(20.0, 50.0, 
                                           50.0, 200.0);
    g2d.draw(line); 
    Rectangle2D.Double rect = new Rectangle2D.Double(100.0, 50.0, 
                                                      60.0, 80.0);
    g2d.draw(rect); // also try g2d.fill(rect);
    Ellipse2D.Double circle = new Ellipse2D.Double(200.0, 100.0, 
                                                   80.0, 80.0);
    g2d.draw(circle); // also try g2d.fill(circle); 
  }
}

Beispiel: Zeichnen einer allgemeinen Form

  • Das Beispiel zeichnet ein "T" mit Hilfe der GeneralPath Klasse

gui_generalpath

Quelltext des Beispiels: MyGeneralPath.java

Beispiel: Zeichnen einer allgemeinen Form

  public void paint(Graphics g) {
    super.paint(g);
    Graphics2D g2d = (Graphics2D) g; // cast to Graphics2D
    GeneralPath gp = new GeneralPath(); 
    gp.moveTo( 50,  50); // start here
    gp.lineTo( 50,  70); // going down
    gp.lineTo(100,  70); // going right
    gp.lineTo(100, 180); // going down
    gp.lineTo(120, 180); // going right
    gp.lineTo(120,  70); // going up
    gp.lineTo(170,  70); // going right
    gp.lineTo(170,  50); // going up
    gp.lineTo( 50,  50); // going left (back to start)
    
    g2d.draw(gp); // also try g2d.fill(gp); 
  }

Gibt es Fragen?

questions

Anregungen oder Verbesserungsvorschläge können auch gerne per E-mail an mich gesendet werden: Kontakt

Weitere Vorlesungsfolien

Folien auf Englisch (Slides in English)