Von C nach Java, Teil 5: Wie eine grafische Oberfläche entsteht

Wurde in einem früheren Artikel das Kommandozeilen-Tool FileCrypter zum Verschlüsseln und Komprimieren von Dateien entwickelt, entsteht nun eine grafische Benutzeroberfläche zur komfortablen Steuerung.

In Pocket speichern vorlesen Druckansicht 52 Kommentare lesen
Lesezeit: 26 Min.
Von
  • Andreas Nieden
Inhaltsverzeichnis

Wurde in einem früheren Artikel das Kommandozeilen-Tool FileCrypter zum Verschlüsseln und Komprimieren von Dateien entwickelt, entsteht nun eine grafische Benutzeroberfläche zur komfortablen Steuerung. Da das Thema und das dafür erstellte Programm komplex sind, geht dieser Artikel auf den Aufbau der GUI und ein weiterer auf die Einbindung, Bedienung und den Ablauf der Dateiverarbeitung ein.

In diesem Beitrag bleiben die C-Beispiele weitgehend außen vor. Das hat seinen Grund darin, dass bei der Entwicklung von GUI-Komponenten mit reinem C das Ende des ökonomisch Machbaren erreicht ist. Es gibt unter C keinen Standard dafür, der sich plattformübergreifend etabliert hat. Das führt unter Windows dazu, dass sich GUI-Anwendungen mit reinem C überwiegend der Win32 API (user32.dll, gdi32.dll etc.) bedienen. Die API aber ist ziemlich schlicht organisiert, der Aufbau und die Implementierung der Bedienung eines Kontrollelements bedürfen vieler Programmzeilen. Beispielsweise ist jedes Kontrollelement in der API ein Window-Objekt, auch eine (später noch genauer beschriebene) Scroll-Leiste. Umso komplizierter und atypischer ist der Aufruf von CreateWindowEx() zum Erzeugen des Kontrollelements. Hier ist viel Dokumentationsliteratur und Probieren erforderlich, um ansprechende Ergebnisse zu erzielen.

Mehr Infos

Alle Artikel der Reihe

In dieser Artikelserie bereits erschienen:

  • Teil 1: Der schnelle Umstieg von der Kommandozeile aus
  • Teil 2: Files, I/O und eine Entwicklungsumgebung
  • Teil 3: HTML-Dokumente aus dem Internet laden
  • Teil 4: Datenkompression und Verschlüsselung
  • Teil 5: Wie eine grafische Oberfläche entsteht

Quellcode zum Artikel

Die im Artikel gezeigten Programmbeispiele finden Sie auf dem FTP-Server von heise Developer zum Download.

Wer denkt, mit C++ portable Programme mit GUIs erstellen zu können, wird ebenfalls enttäuscht. Auch hier hat sich kein De-facto-Standard ergeben, ein Programm beispielsweise unter Windows zu entwickeln und es auf Linux zu portieren. Es gibt zwar unter Windows die MFCs (Microsoft Foundation Classes), jedoch ist das eben ein reines Windows-Konzept. Und selbst hierbei gibt es hinsichtlich der Bedienbarkeit und Ökonomie einige Vorbehalte.

So führen alle Wege hin zu Java. Hier haben die Entwickler von Anfang an an das Erstellen grafischer Nutzeroberflächen gedacht und zunächst mit AWT (Abstract Window Toolkit), später mit Swing eine umfassende API zur Entwicklung grafischer Oberflächen bereitgestellt.

Unter Unix-Systemen setzt die grafische Erweiterung (in TCP/IP-Netzwerken) auf dem X-Window-System und dessen Ressourcen auf. Das hat den Vorteil, dass sich grafische Applikationen von einem PC-Terminal (und einem installierten X-Server) aus aufrufen lassen. Ein weiterer wesentlicher Punkt sind Applets, die Java bietet, um grafische Anwendungen völlig unabhängig vom Betriebssystem von nahezu jedem beliebigen Webbrowser aus ausführen zu lassen. Im Grunde kann man fast jede "grafische" Anwendung auch als Applet umprogrammieren. Wie hoch der Portierungsaufwand dabei ist, hängt lediglich davon ab, inwieweit das bereits zu Beginn der Entwicklung bedacht wurde, und folgerichtig, wie abstrakt die zu implementierenden Klassen entwickelt wurden. Die Applet-Programmierung ist aber nicht Gegenstand des Artikels.

Die Zeiten, in denen kryptisch anmutende Kommandos mit noch kryptischeren Optionen in mühseliger Kleinarbeit über die Tastatur den Programmaufruf starten, sind lange vorbei. Alle bislang für das Kommandozeilen-Tool verwendeten Klassen sollen ohne Änderung in der grafischen Version zum Zuge kommen; die GUI erweitert demnach lediglich das Package net.nieden.FileCrypter um einige zusätzlichen Klassen. Die neue Anwendungsklasse wird nun in der Quelldatei CFileCrypterGUI.java zu finden sein.

Aus Sicht der Programmsteuerung wird weiterhin die Klasse CFileCrypter aufgerufen, wobei die GUI-Version zum Zuge kommt, wenn keine Argumente mit übergeben wurden. Die main()-Methode von CFileCrypter passt man dazu wie folgt an:

public static void main(String[] args) {
try {
if (args.length == 0) {
new CFileCrypterGUI();
} else {
CFileCrypter cc=new CFileCrypter(args);
cc.processFileList();
}
} catch (Exception e) {
e.printStackTrace();
}
}

Das Vorhaben, zu einer Programmfunktion eine grafische Benutzeroberfläche zu entwickeln, bedarf der gründlichen Vorbereitung. Zuerst ist zu klären, was man mit der neuen Benutzersteuerung erreichen soll und wo ihre Vorteile gegenüber der Kommandozeilenversion liegen. Beim vorgestellten Projekt gibt es zwei Ansatzpunkte. Es soll eine komfortable Auswahl der Dateien ermöglichen, die sich im Gegensatz zur Übergabe von Dateien über die Kommandozeile dynamisch gestaltet. Neben der An- und Abwahl von Dateien beziehungsweise ganzen Verzeichnissen soll man durch Selektieren und Markieren von Einträgen die zu bearbeitenden Dateien gezielt auswählen können. Der andere Aspekt bezieht sich auf zusätzliche Optionen, die über die Kommandozeile mit einem vorangestellten "-" übergeben werden. Der Benutzer erhält sie mit geeigneten Kontrollelementen permanent zum Einstellen zur Verfügung gestellt.

Für die Anforderungen eignet sich ein Dialogfenster, das neben einigen Kontrollelementen im oberen Bereich eine Liste mit Dateien enthält. Die Oberfläche stellt sich nach dem Aufruf dem Benutzer wie folgt dar.

So soll die GUI unmittelbar nach dem Aufruf aussehen.

Es ist durchaus empfehlenswert, ein genaues Bild über das Aussehen der zukünftigen Benutzeroberfläche zu haben. Ein Dialog wie oben lässt sich mit Swing-Bordmitteln relativ einfach nachstellen. Zu Beginn der Bemühungen sollte klar sein, ob die Größe des Dialogfensters fest ist oder ob der Benutzer dynamisch die Größe des Fensters anpassen können soll. Bestünde der Dialog nur aus dem Listenelement, wäre die Anpassung des Fensters nur mit geringem Programmieraufwand verbunden. Da allerdings noch Kontrollelemente und Buttons Bestandteil des Dialogs sind, wird in der Ausgabe ein fixer Dialog gebaut. Somit erübrigen sich auch Überlegungen nach dem geeigneten Layout-Manager, die es für Java in großer Zahl gibt, und alle Kontrollelemente bekommen auf dem Eingabefeld ihre feste Größe und Koordinaten.

Die Programmfunktionen und Auswahlmöglichkeiten sollen auf unterschiedliche Weise umgesetzt werden, einerseits um unterschiedliche Benutzerpräferenzen zu bedienen, andererseits aber auch um einfach die verschiedenen Techniken vorzustellen. So gibt es ein Hauptmenü (oben), einige Buttons auf der rechten Seite, und die Liste verfügt über ein Kontextmenü, das über die rechte Maustaste aktiviert wird.

Eine weitere Frage ist, wie der Dialog in Java programmiert wird. Ähnlich wie für C beziehungsweise C++ gibt es in den Java-Entwicklungsumgebungen sogenannte Dialog-Manager, die das "problemlose" Zusammenklicken von Dialogen ermöglichen, aus dem letztlich – mit entsprechenden Plug-ins – die benötigten Klassen generiert werden, die der Entwickler bearbeiten muss. Eclipse bietet beispielsweise einen eigenen Software-Manager, der den Download und die Installation der Plug-ins ermöglicht. Hierin liegt das Problem. Genauso, wie es zahlreiche Dialog-Manager gibt, stehen auch viele Klassenhierarchien zur Verfügung, die erst mal zu verstehen sind und anschließend zu editieren mühselig sein können.

Im Artikel kommen Swing und etwas AWT zum Einsatz. Die Dialoge entstehen ad hoc, und dementsprechend einfach ist es dann, den Dialog mit eigenem Java-Code zum Leben zu erwecken und nach Belieben zu erweitern. Für gewöhnlich erzeugen die diversen Dialog-Manager nur AWT- und Swing-Code. Daher ist es zum späteren Verständnis unumgänglich, sich intensiv mit diesen Techniken zu beschäftigen.

Nun geht es an den Aufbau der Oberfläche aus Abbildung 1. Es sind einige Kontrollelemente zu sehen, ebenso einige grafische Elemente wie sogenannte Group-Boxen, die allerdings kosmetischen Charakter haben. Bewährt hat sich, dieses Gerüst in der Methode void buildGUI() unterzubringen, die entweder im Konstruktor der Anwendungsklasse oder aber vom aufrufenden Programmteil nach dem Erzeugen der Anwendungsklasse ausgeführt wird.