Home | Lehre | Videos | Texte | Vorträge | Software | Person | Impressum, Datenschutzerklärung | Blog RSS

KDevelop 1.4 und Qt Designer 1.1

Grundfunktionen von KDevelop

Projektassistent in KDevelop: Projekt/Neu. Auswahl von C-Konsolenprogramm über leeres Fenster (gut für Dialogfeld-basierte Anwendungen) bis hin zu Fenster mit Unterfenstern (MDI = Multiple Document Interface).

Größere Anwendungen haben View/Document-Klassenstruktur wie bei Microsoft®. Debugger und  Klassenbrowser wie allgemein üblich. Klasse mit .h- und .cpp-Datei hinzufügen: Projekt/Neue Klasse. Methoden, Attribute, Slots oder Signale hinzufügen: Mausklicks rechts in Klassenbrowser.

Menü ändern/hinzufügen: Den XML-Code in [Progammname]rc.ui editieren. In der Methode initActions der jeweiligen Hauptfenster-Klasse (...App genannt) vor dem createGUI-Aufruf entsprechende Aktion erzeugen, z.B. new KAction("Insert Date", 0, this, SLOT(insertDate()), actionCollection() , "insDate" ); Hier wäre insDate der Name der Aktion in der Datei [Programmname]rc.ui-Datei. Dann braucht die Hauptfenster-Klasse (Zeiger auf das angesprochene Objekt: this) natürlich noch eine Slot-Methode insertDate().

Grundfunktionen von Qt Designer

Eigenständige Fenster und Unter-Widgets entwerfen. Dateiformat von Qt Designer ist eine XML-Ausprägung (Dateiname .ui). Daraus entstehen .h- und .cpp-Dateien mit Hilfe des User Interface Compilers (uic). Der wird von KDevelop automatisch aufgerufen. Sonst in makefile aufrufen: uic -o meindialog.h meindialog.ui zum Erzeugen des Header, uic -i meindialog.h -o meindialog.cpp meindialog.ui für cpp-Datei.

.ui-Dateien entsprechen etwa den Ressource-Scripts von Windows(R). Sie werden aber zu echtem Programmcode compiliert, nicht zu nachträglich austauschbaren Datensammlungen (anders als die ...rc.ui-Dateien für Menüs und Toolbars). Bilddaten (Icons, Labels) setzt Qt Designer in ASCII-Codierung um. Sie landen hier also wie auch unter Windows® oder MacOS® üblich in der Programmdatei und stehen nicht getrennt. Alternative: Funktion zum Bilderladen angeben (Mausklick rechts auf Grundfläche: Form Settings).

Buttons, Checkboxen etc. einfach zeichnen. In Property Editor festlegen: Beschriftungen (für Anzeige) und Namen (für Programm) von Buttons, Default-Button, Anfangswerte/-positionen. Listen und Combo-Boxen per Mausklick rechts mit festen Einträgen füllen oder diese bearbeiten. Die KDE-Widgets finden sich im Tool-Menü von QtDesigner.

Tools/Tab Order, um auf übliche Weise festzulegen, wie die Elemente mit Tabulatortaste durchlaufen werden. Das Button-Group-Werkzeug fasst unmrahmte Knöpfe automatisch zusammen. Elemente, die in und über anderen liegen, werden automatisch deren (grafische) Kinder, siehe Window/Object Hierarchy. Im Property Editor kann man direkt Text für Tool Tips und What's This eingeben. Dialog live ausprobieren: Preview-Menü.

Layout-Management in Qt Designer

Beispiel: Button Group aus Radio Buttons anwählen und horizontales Layout anklicken (Layout-Menü). Ebenso mehrere gleichberechtigte Widgets auswählen und horizontales/vertikales/Gitter-Layout anklicken; roter Rahmen markiert die Zusammengehörigkeit. Break Layout: wieder aufbrechen. Layouts verschachteln. Jeweils der äußerste Rahmen lässt sich noch in Größe und Lage einstellen. Dem Grundrahmen Layout zuweisen: in Grundfläche klicken und Layout wählen (leider keine rote Markierung). Wenn Grundrahmen Layout hat, reagiert das Formular auch auf Größenänderungen des Fensters (ausprobieren mit Preview).

Dehnbarer Platz mit horizontalen oder vertikalen Spacern (als Federn dargstellt). Ggf. mehrere Spacer neben- oder übereinander. Weitere Regelmöglichkeiten: Size-Policy-Einstellung der enthaltenen Widgets sowie die Einstellungen Layout Spacing, Layout Margin der Layout-Objekte.

Vorverdrahtung in Qt Designer

Wähle "Connect Signals/Slots vom Edit-Toolbar (nicht! aus dem Menü). Ziehe mit dem dann geänderten Mauswerkzeug Linie von einem Element auf ein anderes. Dialog bietet passende Signals/Slots zum Verdrahten an. Problem bei KDE-Widgets: kaum Slots sichtbar; Qt Designer zeigt wohl nur die public-Elemente. Für das Formular kann man bereits Slots anlegen: Edit/Slots. Verdrahten mit Slots oder Signals des Formulars: Linie auf Grudfläche beginnen oder dort enden lassen.

Anwendungsbeispiele: andere Elemente grau schalten, wenn bestimmte Checkbox aktiviert oder deaktiviert; OK-Knopf festlegen: clicked() des Knopfs mit accept() verbinden. Mit Preview testen.

Qt Designer im Zusammenspiel mit KDevelop

Aus KDevelop-Projekt Datei/Neu ruft Qt Designer auf. Dort nachher nur speichern, keinen neuen Dateinamen vergeben. Dialog erstellen; in KDevelop compilieren. Der Name des umgebenden Formulars wird nachher zum Namen der Klasse; .h- und .cpp-Datei heißen dagegen nach der .ui-Datei. Also besser das Formular nicht auf dem Namen "Form1" lassen, sondern Formular und ui-Datei identisch benennen.

Header-Datei des Dialogs: Alle Elemente sind sofort unter den in Qt Designer vergebenen Namen verfügbar. Die Elemente sind public, damit eine Klasse, die den Dialog aufruft, Werte setzen und lesen kann.

Problem: Wie schreibt man komplexere Interaktionen, die sich nicht in Qt Designer verdrahten lassen? Wie schreibt man einen Konstruktor, der komplexere Initialisierungen vornimmt? Denn: Nach dem nächsten Editieren in Qt Designer und anschließendem Neukompilieren sind alle Änderungen in den generierten .h- und .cpp-Dateien verloren.

Lösung: mit einer Dialog-Implementierungsklasse MeinDialogImpl von der generierten Dialogklasse MeinDialog erben. Netterweise sind die neu angelegten Slots virtuelle Methoden. Erstellen der neuen Klasse: Projekt/Neue Klasse, als Basisklasse die Dialogklasse eintippen, "Von QWidget abgeleitete Klasse erstellen" anklicken. Letzteres führt dazu, dass KDevelop in die Header-Datei das für Signals und Slots nötige Makro Q_OBJECT einfügt.

Vorsicht: Die so erzeugte Klasse ist zunächst ein nichtmodaler Dialog. Für modalen Dialog im Konstruktor der neuen Klassen den Aufruf der urspünglichen Dialogklasse um ein true als dritter Variable ergänzen: MeinDialogImpl::MeinDialogImpl(QWidget *parent, const char *name ) : MeinDialog(parent, name, true) {}

Aufruf als modaler Dialog läuft wie gehabt:
#include "meindialogimpl.h"
//...
MeinDialogImpl d(Zeiger_auf_Fenster_darunter);
d.exec();

Vor allem für die KDevelop-Vorlage "KDE 2 Mini" ist es günstig, ein mit Qt Designer gebautes Widget (keinen Dialog!) als Anwendungsfensters zu benutzen (vgl. dialogfeldbasierte Anwendung in Microsoft® Visual C++®). Dort einfach in der Fensterklasse von der Widgetklasse aus Qt Designer erben, statt schlicht von QWidget. In den größeren KDevelop-Projekten mit "echtem" Fenster (KMainWindow) kann man ein Widget aus Qt Designer per setCentralWidget als View benutzen.

Internationalisierung (I18N)

An fast allen Stellen, wo konstante C-Strings im Quelltext stehen, kann man stattdessen i18n("") schreiben. Dieses i18n ist ein in klocale.h definiertes Makro. Zur Laufzeit erzeugt es -- mit entsprechender Vorbereitung -- einen passenden übersetzten QString (Vorsicht: keinen C-String). Alle Programme sollen zunächst in Englisch entstehen und dann mit Hilfe dieser Technik internationalisiert werden.

i18n kann auch mit zwei Argumenten aufgerufen werden, um Kommentare der Art i18n("log file, not logarithm", "log"); an den Übersetzer zu reichen. So kann man auch im Englischen gleiche Strings an verschiedenen Stellen verschieden übersetzen. Um die Wortreihenfolge für die Übersetzung variabel zu halten, soll man statt
QString msg=i18n("Do you want to replace ")+oldFile+i18n(" with ")+newFile+"?";
besser verwenden:
QString msg=i18n("Do you want to replace %1 with %2").arg(oldFile).arg(newFile);

i18n darf erst zu einem Zeitpunkt aufgerufen werden, zu dem das KApplication-Objekt exisitiert. Denn das kennt die aktuelle Sprache und steuert die Übersetzung. Vorher kann man allenfalls I18N_NOOP("...") benutzen. Dann wird der String zwar extrahiert, aber nicht live übersetzt.

Auf Projekt/"Neue Übersetzung hinzufügen" extrahiert KDevelop (falls noch nicht geschehen) alle gekennzeichneten Strings auch aus Menü- und Dialog-Definitionen und führt sie in einer Datei [Programmname].pot zusammen (.pot = portable object template). Aus dieser Datei erzeugt KDevelop dann zum Beispiel für Deutsch eine Datei de.po (.po = portable object). Die .po-Dateien für die verschiedenen Sprachen liegen wie die eine .pot-Datei im Unterverzeichnis po des Projekts. In dieser Datei ergänzt man mit KBabel die Übersetzungen (einfach in KDevelop die .po-Datei anklicken). Sind die Strings wegen Programmänderungen zu aktualisieren, wählt man in KDevelop die Funktion Projekt/"Meldungen erstellen und verbinden".

Diese .po-Datei muss noch in eine Datenbank umgewandelt werden, Dateiendung .mo (machine object). Das geht mit msgfmt de.po -o [programmname].mo. Damit ein Programm deutsch erscheint, muss die Datei [programmname].mo etwa unter SuSE 7.2 in opt/kde2/share/locale/de/LC_MESSAGES liegen. Das Erzeugen von .mo übernimmt KDevelop nicht. Während der Entwicklung kann man das zu Fuß erledigen; bei der Installation des entwickelten Programms passiert es dann automatisch.

Lokalisierung oder L10N: Die Klasse KLocale sorgt nicht nur für Übersetzungen, sondern auch für die landesübliche Darstellung zum Beispiel von Währung und Uhrzeit:
#include <qdatetime.h>
//...
KLocale l;
QString s = l.formatDate(QDate::currentDate()));

Distributionen erstellen

Einfache Lösung: Projekt/"Distribution erstellen"/Quellen-tgz. Die so entstehenden tgz-Dateien installiert man auf übliche Art:

tar -xzf [Name].tgz
[mit cd ins Verzeichnis wechseln]
./configure
make
[root-Rechte verschaffen, z.B. mit su]
make install

Die .mo-Datei landet allerdings falsch unter /opt/kde/share/locale/de/LC_MESSAGES/ statt .../kde2/...

Für den Anwender einfacher und für das System sauberer wäre es, das noch in ein rpm-Paket umzuwandeln. KDevelop besitzt dazu (bislang) undokumentierte Hilfen.