Weitere Grafikelemente

Inhalt

 

 

Texteingabe und Textausgabe

 

Benutzergesteuerte Layouts

 

Auswahlfelder

 

Menüs

 

Dialoge

 

Übungsaufgaben

Texteingabe und Textausgabe

Wir haben schon im Kapitel über Grafikausgaben und im Kapitel über Events eine Reihe von Komponenten (Panel, Canvas, Button) kennen gelernt, die sich in Java-Applikationen mit graphischer Benutzeroberfläche einsetzen lassen. Dort hatten wir auch schon Layouts kennen gelernt zur Anordnung dieser Komponenten. Wir werden zunächst die wichtigsten Komponenten kennen lernen, mit denen sich Text ein- und ausgeben lässt.

Die Komponente zum Anzeigen eines statischen Textes heißt JLabel. Der Text lässt sich entweder mit dem Konstruktor oder mit der Methode setText setzen. Ein Label ist immer einzeilig.

Die Komponente, mit der der Benutzer einzeiligen Text ein- und ausgeben kann, ist JTextField. Die Textvorgabe erfolgt genau wie beim Label. Man kann das JTextField nicht-editierbar machen, um nur einen Text anzuzeigen. Gewöhnlich will man aber, dass der Benutzer den angezeigten Text verändern kann. Dann kann man den Text einfach mit getText auslesen. Ein JTextField kann auch ein ActionEvent produzieren, wenn der Benutzer die Enter-Taste drückt.

Will man mehrzeiligen Text ein- und ausgeben, so verwendet man eine JTextArea. Im Unterschied zum JTextField erzeugt diese Methode kein Event, wenn die Enter-Taste gedrückt wird, sondern erzeugt dadurch einen neuen Paragraphen. Dieses Verhalten kann man aber ändern. Man verwendet gewöhnlich kein Event dieser Komponenten, sondern wertet den Inhalt z.B. beim Druck auf einen Knopf aus.

Damit wir im Text scrollen können, verwenden wir eine JScrollPane. Dies ist eine Komponente, die ein JTextField aufnehmen kann und Scrollbalken anzeigt, sofern dies notwendig ist.

In diesem Programm wird die TextArea nicht bearbeitbar gemacht. Alle Eingaben im TextField werden aber dort an den vorhandenen Text angehängt.

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

class TestFrame extends JFrame
        implements ActionListener
{
    JTextArea textarea;
    JTextField textfield;

    public TestFrame ()
    {
        super("Test");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        setLayout(new BorderLayout());
        setSize(500, 400);

        // Label:
        add("North", new JLabel("Test", JLabel.CENTER));

        // TextArea:
        textarea = new JTextArea();
        JScrollPane OutP = new JScrollPane(textarea);
        add("Center", OutP);
        OutP.setPreferredSize(new Dimension(400, 400));
        textarea.setEditable(false);

        // TextField:
        add("South", textfield = new JTextField());
        textfield.addActionListener(this);

        pack();
        setLocationRelativeTo(null);
        setVisible(true);
    }

    @Override
    public void actionPerformed (ActionEvent e)
    {
        if (e.getSource() == textfield) // enter in TextField
        {
            textarea.append(textfield.getText() + "\n");
            textfield.setText("");
        }
    }
}

public class Test
{
    public static void main (String args[])
    {
        new TestFrame();
    }
}

Benutzergesteuerte Layouts

Wir besprechen hier zwei Layout-Varianten, die vom Benutzer verändert werden können.

JSplitPlane erzeugt eine vertikal oder horizontal geteilte Ansicht, wobei der Benutzer die Teilung aktiv verschieben kann. Der Container enthält also zwei Komponenten. Deren Minimalgröße bestimmt, wie weit sich der Schieber nach rechts oder links verschieben lässt. Wir setzen daher die Minimalgröße unserer Canvas auf 10 mal 10 Pixel. Zu beachten ist noch, dass der übrige Raum zwischen den Komponenten verteilt wird. Wir wollen eine gleiche Aufteilung und setzen daher das Aufteilungsgewicht auf 0.5.

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSplitPane;

/**
 * Eine Canvas, die mit Farbe gefüllt wird.
 */
class TestCanvas extends Canvas
{
    Color C;

    public TestCanvas (Color c)
    {
        C = c;
        setMinimumSize(new Dimension(10, 10));
    }

    @Override
    public void paint (Graphics g)
    {
        Dimension d = getSize();
        g.setColor(C);
        g.fillRect(0, 0, d.width, d.height);
    }
}

/**
 * Das ist ein Panel mit zwei horizontalen Farbfeldern. Der Benutzer kann die
 * Trennung verschieben.
 */
class TestPanel extends JPanel
{
    public TestPanel ()
    {
        setPreferredSize(new Dimension(400, 200));
        
        // Erzeuge eine SplitPane mit zwei Farbfeldern:
        JSplitPane pane = new JSplitPane(
                JSplitPane.HORIZONTAL_SPLIT,
                new TestCanvas(Color.RED),
                new TestCanvas(Color.GREEN));
        pane.setResizeWeight(0.5);
        
        // In der Mitte hinzufügen:
        setLayout(new BorderLayout());
        add("Center", pane);
    }
}

public class Test extends JFrame
{
    public Test ()
    {
        super("Test");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        add("Center", new TestPanel());

        pack();
        setLocationRelativeTo(null);
        setVisible(true);
    }

    public static void main (String args[])
    {
        new Test();
    }
}

Die andere Art, mehrere Komponenten auf kleinem Raum unterzubringen ist JTabbedPane.

Dazu müssen wir nur den Code folgendermaßen ändern.

JTabbedPane pane=new JTabbedPane();
pane.add("Rot",new TestCanvas(Color.RED));
pane.add("Grün",new TestCanvas(Color.GREEN));

Es gibt noch die Möglichkeit, Icons anstelle von Text und Tooltips (Texte, die beim Verharren der Maus über dem Reiter erscheinen) zu verwenden.

Auswahlfelder

Oftmals will man den Benutzer aus mehreren Möglichkeiten auswählen lassen. Dazu gibt es die JComboBox. Beim Klick auf ein Klappfeld öffnet sich eine Liste mit Möglichkeiten. Wählt der Benutzer eine davon aus, so wird ein ActionEvent ausgelöst. Im folgenden Programm fangen wir dieses Event ab und stellen das Resultat in einen Label dar.

Die Klasse JComboBox ist generisch und man kann den Typ der Elemente spezifizieren. Wir verwenden hier Strings.

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class Test extends JFrame
        implements ActionListener
{
    JLabel label;
    JComboBox<String> box;

    String strings[] =
    { "Apfel", "Birne", "Kirsche" };

    public Test ()
    {
        super("Test");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        label = new JLabel("", JLabel.CENTER);
        label.setPreferredSize(new Dimension(100, 50));

        box = new JComboBox<String>(strings);
        box.addActionListener(this);

        setLayout(new BorderLayout());
        add("Center", label);
        add("South", box);

        pack();
        setLocationRelativeTo(null);
        setVisible(true);
    }

    @Override
    public void actionPerformed (ActionEvent e)
    {
        if (e.getSource() == box)
        {
            if (box.getSelectedIndex() >= -1)
            {
                label.setText(box.getSelectedItem().toString());
            }
        }
    }

    public static void main (String args[])
    {
        new Test();
    }
}

Man kenn den ausgewählten Index abfragen oder auch das ausgewählte Objekt, das man mit toString umwandeln kann. Natürlich kann man die Auswahl auch über das Programm setzen. Näheres findet man in der Dokumentation.

Will man alle Auswahlmöglichkeiten gleichzeitig darstellen, so gibt es JList. Diese neue Komponente erzeugt ein Ereignis vom Typ ListSelectionEvent. Es muss daher ein anderes Paket eingebunden werden. Im folgenden Programm betten wir die Liste außerdem mit Scrollbalken ein, die erscheinen würden, wenn die Liste zu lang wäre.

import java.awt.BorderLayout;
import java.awt.Dimension;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

public class Test extends JFrame
        implements ListSelectionListener
{
    JLabel label;
    JList<String> list;

    String strings[] =
    { "Apfel", "Birne", "Kirsche" };

    public Test ()
    {
        super("Test");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        label = new JLabel("", JLabel.CENTER);
        label.setPreferredSize(new Dimension(100, 50));
        list = new JList<String>(strings);
        list.addListSelectionListener(this);

        setLayout(new BorderLayout());
        add("Center", label);
        add("South", new JScrollPane(list));

        pack();
        setLocationRelativeTo(null);
        setVisible(true);
    }

    @Override
    public void valueChanged (ListSelectionEvent e)
    {
        if (e.getSource() == list)
        {
            if (list.getSelectedIndex() >= -1)
            {
                label.setText(list.getSelectedValue().toString());
            }
        }
    }

    public static void main (String args[])
    {
        new Test();
    }

}

Menüs

Gemeint sind die Auswahlmenüs, die unterhalb der Titelzeile von Fenstern erscheinen. Es gibt daneben in Java 1.1 auch noch Popup-Menüs, die mitten auf einer Seite erscheinen können.

Ein Menü besteht aus einem MenuBar, der verschiedene Menu-Objekte enthält. Jedes ist ein Klappmenü, das wiederum MenuItem-Objekte enthält, die der Benutzer letztendlich wählen kann. Das Menü wird im Konstruktor des Frames aufgebaut. Das entsprechende Code-Segment sieht so aus:

// Erzeuge Menueleiste
JMenuBar menu=new JMenuBar()
setMenuBar(menu);
// Ezeuge ein Menue
JMenu files=new JMenu("Files");
menu.add(files);
// Erzeuge darin einen Menue-Eintrag
JMenuItem ItemClose=new JMenuItem("Close");
ItemClose.setActionListener(this);
files.add(ItemClose);

Wie man sieht, ist der Prozess dreistufig: Menüleiste, Menü und Menüeintrag. Man kann allerdings auch Menüs in Menüs schachteln. Dies erzeugt Aufklapp-Menüs, wie man sie von graphischen Benutzoberflächen her kennt.

Es gibt neben normalen JMenuItem auch JCheckBoxItem, die ein Häkchen erhalten, wenn sie angewählt sind.

Popup-Menüs werden gewöhnlich durch einen rechten Mausklick auf das Fenster ausgelöst. Das folgende Programm demonstriert die Erzeugung eines Menüs und eines Popup-Menüs. Die Ereignisse des verwendeten CheckboxMenuItem "Ignore" werden hier nicht abgefangen. Stattdessen wird im Bedarfsfall dessen Status abgefragt.

Menu 

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;

class TestFrame extends JFrame
        implements ActionListener
{
    JMenuItem close;
    JCheckBoxMenuItem ignore;
    JPopupMenu popup;
    JButton popupclose;

    public TestFrame ()
    {
        // build up the menu bar
        JMenuBar m = new JMenuBar();
        setJMenuBar(m);

        JMenu menu = new JMenu("Test"); // first menu
        m.add(menu);

        // a normal menu item
        close = new JMenuItem("Close"); // an item
        close.addActionListener(this);
        menu.add(close);

        // a checkbox item
        menu.add(ignore = new JCheckBoxMenuItem("Ignore Close in Menu"));
        ignore.setState(true);

        // popup menu:
        popup = new JPopupMenu();
        popupclose = new JButton("Close");
        popup.add(popupclose);
        popupclose.addActionListener(this);
        add(popup);

        JPanel panel = new JPanel();
        add("Center", panel);

        panel.addMouseListener( // for the popup menu
                new MouseAdapter()
                {
                    @Override
                    public void mousePressed (MouseEvent e)
                    {
                        if (SwingUtilities.isRightMouseButton(e))
                        // right mouse click
                        {
                            popup.pack();
                            popup.show(e.getComponent(), e.getX(), e.getY());
                        }
                    }
                });

        setSize(600, 600);
        setLocationRelativeTo(null);
        setVisible(true);
    }

    @Override
    public void actionPerformed (ActionEvent e)
    {
        if (e.getSource() == close
                && !ignore.getState())
        {
            dispose();
            System.exit(0);
        }

        else if (e.getSource() == popupclose)
        {
            System.exit(0);
        }
    }
}

public class Test
{
    public static void main (String args[])
    {
        new TestFrame();
    }
}

Das Popup-Menu wird über einen MouseAdapter aktiviert. Dazu wird auf Druck der rechten Maustaste reagiert. Das Popup-Menü erzeugt nach seiner Anzeige Events, wenn der Benuter einen Menüpunkt auswählt. Es informiert dann die registrierten Listener über diese Events, genau wie das normale Menü.

Dialoge

Dialoge sind kleine Fenster, die zu einen Frame gehören, und für Benutzereingaben eingeblendet werden. Beispiele sind Ja/Nein-Abfragen, Suchen und Ersetzen oder auch der Dialog zur Dateiauswahl.

Dialoge können modal oder nicht-modal sein.

Die Erzeugung eines Dialogs ist ähnlich wie die Erzeugung eines Fensters. Man erzeugt einer Instanz der Dialog-Klasse. Dann muss der Dialog noch mit setVisible(true). angezeigt werden. Bei nicht-modalen Dialogen läuft das Programm danach normal weiter.

Als Beispiel erzeugen wir einen Dialog, der abfragt, ob das Fenster wirklich geschlossen werden soll. Wir machen den Dialog natürlich modal.

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

class CloseQuestion extends JDialog
        implements ActionListener
{
    private boolean Yes = false;

    public CloseQuestion (JFrame f)
    {
        super(f, "Close", true);

        // call constructor of dialog with modal-flag true
        // Label for the question:
        add("North", new JLabel("Really close?"));

        // Panel for the yes/no buttons
        JPanel p = new JPanel();
        JButton b;
        p.add(b = new JButton("Yes"));
        b.addActionListener(this);
        p.add(b = new JButton("No"));
        b.addActionListener(this);
        add("South", p);

        // pack set it 100x100 off the frame and show it
        // (blocking the frame)
        pack();
        setLocation(f.getLocation().x + 100, f.getLocation().y + 100);
        setVisible(true);
    }

    @Override
    public void actionPerformed (ActionEvent e)
    {
        if (e.getActionCommand().equals("Yes"))
        // pressed the yes button
        {
            Yes = true;
        }

        dispose(); // frame continues its job
    }

    public boolean isYes () // to ask for