KDE-Programmierung: KProcess
In diesem Teil des Workshops wird Word2HTML erstmals eine sinnvolle Aufgabe erfüllen.
Wie geht's weiter?
In diesem Teil des Workshops wird Word2HTML erstmals eine sinnvolle Aufgabe erfüllen. Wir werden das Kommandozeilenprogramm mswordview ausführen und ihm den Pfad einer DOC-Datei übergeben, die der Anwender in einem Dateiauswahldialog auswählen kann. Diese Datei wird dann von mswordview in eine HTML-Datei konvertiert. Die Ausgabe von mswordview lassen wir im Programmfenster anzeigen. Wir haben also ein klassisches Frontend, das die Funktionalität eines Kommandozeilenprogrammes über eine grafische Oberfläche bereitstellt.
Was ist KProcess?
Normalerweise müssten wir auf Systemaufrufe zurückgreifen, um mswordview aus Word2HTML heraus auszuführen. Da das sehr unkomfortabel und fehlerträchtig ist, stellen die KDE-Libs die Klasse KProcess zur Verfügung. Sie erlaubt es auf einfache Weise, fremde Programme zu starten und auf ihre Ausgaben zu reagieren. Unter http://developer.kde.org finden Sie eine Referenz mit allen Klassen der KDE-Libs.
Der Code
Laden Sie einfach die neuen Quellen herunter und überschreiben die alten damit. Achten Sie aber darauf, dass Sie in KDevelop unter auf der Registrierkarte »kfm« und »kfile« ausgewählt haben.
/* toplevel.h */ #ifndef _TOPLEVEL_H_ #define _TOPLEVEL_H_ #include <kapp.h> #include <ktmainwindow.h> #include <kmenubar.h> #include <qpopupmenu.h> #include <qmessagebox.h> #include <kfiledialog.h> #include <qmultilinedit.h> #include <kprocess.h> #include <qfileinfo.h> class TopLevel : public KTMainWindow { Q_OBJECT public: TopLevel(); void closeEvent(QCloseEvent *); private slots: void aboutApp(); void openFile(); void getOutput(KProcess *, char *, int); private: QMultiLineEdit *outputDisplay; KProcess proc; }; #endif
Erklärung
void openFile(); void getOutput(KProcess *, char *, int);
Es werden zwei neue Slots deklariert. Der erste wird ausgeführt werden, um einen Dateiauswahldialog zu öffnen und die ausgewählte Datei zu konvertieren. Der zweite wird die Ausgaben von mswordview entgegennehmen und innerhalb des Programmfensters anzeigen.
QMultiLineEdit *outputDisplay; KProcess proc;
Hier wird ein Zeiger auf die Klasse QMultiLineEdit und ein Objekt der Klasse KProcess deklariert. Die Klasse QMultiLineEdit ist ein ganz gewöhnliches Editorfeld, wie es z.B. in KEdit Verwendung findet. Wir verwenden sie um die Ausgaben von mswordview darzustellen.
/* toplevel.cpp */ #include "toplevel.h" TopLevel::TopLevel() { QPopupMenu *file = new QPopupMenu; file->insertItem(i18n("Open ..."), this, SLOT(openFile())); file->insertSeparator(); file->insertItem(i18n("&Quit"), kapp, SLOT(quit())); QPopupMenu *help = new QPopupMenu; help->insertItem(i18n("&About"), this, SLOT(aboutApp())); KMenuBar *menu = new KMenuBar(this); menu->insertItem(i18n("&File"), file); menu->insertSeparator(); menu->insertItem(i18n("&Help"), help); setMenu(menu); outputDisplay = new QMultiLineEdit(this); outputDisplay->setReadOnly(true); setView(outputDisplay); connect(&proc, SIGNAL(receivedStdout(KProcess *, char *, int)), this, SLOT(getOutput(KProcess *, char *, int))); connect(&proc, SIGNAL(receivedStderr(KProcess *, char *, int)), this, SLOT(getOutput(KProcess *, char *, int))); resize(500,400); setCaption("Word2HTML"); } void TopLevel::closeEvent(QCloseEvent *) { kapp->quit(); } void TopLevel::aboutApp() { QMessageBox::about(this, "About Word2HTML","Hello World"); } void TopLevel::openFile() { QString filename = KFileDialog::getOpenFileName(NULL, "*.doc"); if (filename == NULL) return; QFileInfo file(filename); if (!file.exists()) return; if (file.isDir()) return; proc << "mswordview"; proc << filename; proc.start(KProcess::NotifyOnExit, KProcess::AllOutput); } void TopLevel::getOutput(KProcess *, char *data, int len) { char dst[len+1]; memmove(dst,data,len); dst[len]=0; outputDisplay->append(dst); }
Erklärung
file->insertItem(i18n("Open ..."), this, SLOT(openFile()));
Im Menü openFile()
verbunden.
outputDisplay = new QMultiLineEdit(this); outputDisplay->setReadOnly(true);
Unser Ausgabefeld für mswordview wird erzeugt. Da es nicht editierbar sein soll, wird es auf »read only« gesetzt.
setView(outputDisplay);
Das Ausgabefeld wird innerhalb des Fensters maximiert. Bei jeder Veränderung des Fensters wird es angepasst.
connect(&proc, SIGNAL(receivedStdout(KProcess *, char *, int)), this, SLOT(getOutput(KProcess *, char *, int)));
Das Objekt proc
von der Klasse KProcess
sendet ein Signal aus, sobald das von ihm gestartete Programm eine Ausgabe auf den Standard-Ausgabekanal macht. Diese Ausgabe liefert es in Form eines Zeigers auf char und eines Integerwertes, der die Länge angibt, auch gleich mit. Dieses Signal wird nun mit unserem Slot getOutput(KProcess *, char *, int)
verbunden. Er nimmt diese Daten entgegen und zeigt sie auf unserem Ausgabefeld an.
connect(&proc, SIGNAL(receivedStderr(KProcess *, char *, int)), this, SLOT(getOutput(KProcess *, char *, int)));
Dasselbe noch einmal, diesmal eben für die Standard-Fehlerausgabe.
void TopLevel::openFile() { QString filename = KFileDialog::getOpenFileName(NULL, "*.doc"); if (filename == NULL) return;
Mit der Funktion getOpenFileName()
der Klasse KFileDialog wird ein Dateiauswahldialog angezeigt. Sein Rückgabewert, also die ausgewählte Datei, wird in einem Objekt filename
vom Typ QString gespeichert. Wenn der Inhalt von filename
NULL ist, also wenn der Anwender gewählt hat, wird die komplette Funktion mit return
abgebrochen.
QFileInfo file(filename); if (!file.exists()) return; if (file.isDir()) return;
Es wird geprüft, ob filename
auf eine existierende Datei verweist. Wenn nicht, wird die Funktion abgebrochen.
proc << "mswordview"; proc << filename; proc.start(KProcess::NotifyOnExit, KProcess::AllOutput); }
Das Objekt wird mit dem Namen des auszuführenden Programms und seinen Parametern (in diesem Fall nur dem Namen der zu konvertierenden Datei) »gefüttert« und gestartet.
void TopLevel::getOutput(KProcess *, char *data, int len) { char dst[len+1]; memmove(dst,data,len); dst[len]=0;
Die Ausgaben von mswordview werden entgegengenommen. Da wir nur den Zeiger auf einen String bekommen, der zu dem Zeitpunkt, wo er angezeigt werden soll, nicht mehr existiert, wird er in ein Array vom Typ char kopiert.
outputDisplay->append(dst); }
Der String, den wir so eben kopiert haben, wird auf dem Ausgabefeld ausgegeben.