Development/Tutorials/Saving and loading (de): Difference between revisions

From KDE TechBase
mNo edit summary
No edit summary
 
(31 intermediate revisions by 4 users not shown)
Line 1: Line 1:
{{Template:I18n/Language Navigation Bar|Development/Tutorials/Saving_and_loading}}
 


{{TutorialBrowser (de)|
{{TutorialBrowser (de)|
Line 5: Line 5:
series=Anleitung für Anfänger|
series=Anleitung für Anfänger|


name=Laden und speichern von Dateien|
name=Laden und Speichern von Dateien|


pre=[[Development/Tutorials/Using_KActions (de)|Anleitung 3 - KActions benutzen]]|
pre=[[Development/Tutorials/Using_KActions (de)|Anleitung 3 - KActions benutzen]]|
Line 16: Line 16:
==Zusammenfassung==
==Zusammenfassung==


Nun da wir ein rudimentäres Text Editor Interface erstellt haben, ist es an der Zeit etwas Nützliches zu machen. Grundsätzlich muss ein Text Editor Dateien laden, nach Bearbeitung oder Erzeugung speichern und neue Dateien erstellen.
In diesem Kapitel werden Sie lernen, wie man grundsätzliche Datei-Aktionen wie Laden und  Speichern mithilfe der KIO Bibliothek einbindet.


KDE stellt eine Anzahl von Klassen bereit um das Arbeiten mit Dateien für die Entwickler deutlich zu vereinfachen. Die KIO Bibliothek ermöglicht es Dateien auf einfache Weise über Netzwerk-transparente Protokolle anzusteuern und stellt auch Standard Datei-Dialoge bereit.
KDE stellt eine Anzahl von Klassen bereit um das Arbeiten mit Dateien für die Entwickler deutlich zu vereinfachen. Die KIO Bibliothek ermöglicht es Dateien auf einfache Weise über Netzwerk-transparente Protokolle anzusteuern und stellt auch Standard Dateidialoge bereit.


[[image:introtokdetutorial4.png|frame|center]]
[[image:introtokdetutorial4.png|frame|center]]
Line 25: Line 25:


===main.cpp===
===main.cpp===
<code cppqt n>
<syntaxhighlight lang="cpp-qt" line>
#include <KApplication>
#include <KApplication>
#include <KAboutData>
#include <KAboutData>
Line 46: Line 46:
   return app.exec();
   return app.exec();
}
}
</code>
</syntaxhighlight>
<tt>main.cpp</tt> hat sich seit der dritten Anleitung nicht verändert, ausser das jeder Bezug zu "tutorial 3" zu "tutorial 4" geändert wurde.
<tt>main.cpp</tt> hat sich seit der dritten Anleitung nicht verändert, ausser das jeder Bezug zu 'tutorial 3' zu 'tutorial 4' geändert wurde.


===mainwindow.h===
===mainwindow.h===
<code cppqt n>
<syntaxhighlight lang="cpp-qt" line>
#ifndef MAINWINDOW_H
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#define MAINWINDOW_H
Line 78: Line 78:


#endif
#endif
</code>
</syntaxhighlight>
Da wir unserem Programm die Fähigkeit geben wollen, Dateien zu laden und zu speichern müssen wir Funktionen hinzufügen, die diese Arbeit erledigen werden. Da die Funktionen durch Qt's [http://doc.trolltech.com/latest/signalsandslots.html signal/slot]-Mechanismus aufgerufen werden, müssen wir definieren, dass diese Funktionen Slots sind, wie wir dies auf Zeile 19 machen. Da wir Slots in diesem Header-File benutzen müssen wir auch das [http://doc.trolltech.com/latest/qobject.html#Q_OBJECT <tt>Q_OBJECT</tt>] Makro hinzufügen.
Da wir unserem Programm die Fähigkeit geben wollen, Dateien zu laden und zu speichern müssen wir Funktionen hinzufügen, die diese Arbeit erledigen werden. Da die Funktionen durch Qt's [http://doc.trolltech.com/latest/signalsandslots.html signal/slot]-Mechanismus aufgerufen werden, müssen wir definieren, dass diese Funktionen Slots sind, wie wir dies auf Zeile 19 machen. Da wir Slots in diesem Header-File benutzen, müssen wir auch das [http://doc.trolltech.com/latest/qobject.html#Q_OBJECT <tt>Q_OBJECT</tt>] Makro hinzufügen.


Wir werden auch den Dateinamen der momentan geöffneten Datei verfügbar haben wollen, also definieren wir einen <tt>{{qt|QString}} fileName</tt>.
Wir werden auch den Dateinamen der momentan geöffneten Datei verfügbar haben wollen, also definieren wir einen <tt>{{qt|QString}} fileName</tt>.


===mainwindow.cpp===
===mainwindow.cpp===
<code cppqt n>
<syntaxhighlight lang="cpp-qt" line>
#include "mainwindow.h"
#include "mainwindow.h"


Line 196: Line 196:
   }
   }
}
}
</code>
</syntaxhighlight>


===tutorial4ui.rc===
===tutorial4ui.rc===
<code xml n>
<syntaxhighlight lang="xml" line>
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
<gui name="tutorial4"
<gui name="tutorial4" version="1">
    version="1"
  <ToolBar name="mainToolBar" >
    xmlns="http://www.kde.org/standards/kxmlgui/1.0"
    <text>Main Toolbar</text>
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    <Action name="clear" />
    xsi:schemaLocation="http://www.kde.org/standards/kxmlgui/1.0
  </ToolBar>
                        http://www.kde.org/standards/kxmlgui/1.0/kxmlgui.xsd" >
 
   <MenuBar>
   <MenuBar>
     <Menu name="file" >
     <Menu name="file" >
Line 212: Line 213:
     </Menu>
     </Menu>
   </MenuBar>
   </MenuBar>
  <ToolBar name="mainToolBar" >
    <text>Main Toolbar</text>
    <Action name="clear" />
  </ToolBar>
</gui>
</gui>
</code>
</syntaxhighlight>
Dies ist identisch mit <tt>tutorial3ui.rc</tt> aus Anleitung 3 ausser dass <tt>name</tt> zu 'tutorial4' geändert wurde. Wir müssen keine Informationen über irgendeine der <tt>KStandardAction</tt>s hinzuzufügen da die Platzierung dieser Aktionen automatisch durch KDE erfolgt.
Dies ist identisch mit <tt>tutorial3ui.rc</tt> aus Anleitung 3 ausser dass <tt>name</tt> zu 'tutorial4' geändert wurde. Wir müssen keine Informationen über irgendeine der <tt>KStandardActions</tt> hinzuzufügen da die Platzierung dieser Aktionen automatisch durch KDE erfolgt.


==Erklärung==
==Erklärung==
Line 221: Line 228:


Als erstes fügen wir
Als erstes fügen wir
<code cppqt>
<syntaxhighlight lang="cpp-qt">
fileName(QString())
fileName(QString())
</code>
</syntaxhighlight>
der <tt>MainWindow</tt> Konstruktor-Liste auf Zeile 16 hinzu. Das stellt sicher, dass <tt>fileName</tt> von Anfang an leer ist.
der <tt>MainWindow</tt> Konstruktor-Liste auf Zeile 16 hinzu. Das stellt sicher, dass <tt>fileName</tt> von Anfang an leer ist.


Line 230: Line 237:
Als nächstes werden wir das äusserliche Interface für den Benutzer bereitstellen, so dass er der Anwendung mitteilen kann zu laden und zu speichern. Wie mit der <tt>quit</tt> Aktion in Anleitung 3 werden wir <tt>KStandardActions</tt> verwenden. Auf Zeilen 37 bis 47 werden wir die Aktionen auf die selbe Weise hinzufügen wie für die <tt>quit</tt> Aktion. Für jedes einzelne werden wir es mit dem richtigen Slot verbinden den wir in der Header Datei definiert haben.
Als nächstes werden wir das äusserliche Interface für den Benutzer bereitstellen, so dass er der Anwendung mitteilen kann zu laden und zu speichern. Wie mit der <tt>quit</tt> Aktion in Anleitung 3 werden wir <tt>KStandardActions</tt> verwenden. Auf Zeilen 37 bis 47 werden wir die Aktionen auf die selbe Weise hinzufügen wie für die <tt>quit</tt> Aktion. Für jedes einzelne werden wir es mit dem richtigen Slot verbinden den wir in der Header Datei definiert haben.


TODO:Der Rest muss noch übersetzt werden.
===Erstellen eines neuen Dokuments===


===Creating a new document===
Die erste Funktion die wir erstellen ist <tt>newFile()</tt>.


The first function we create is the <tt>newFile()</tt> function.
<syntaxhighlight lang="cpp-qt">
<code cppqt>
void MainWindow::newFile()
void MainWindow::newFile()
{
{
Line 241: Line 247:
   textArea->clear();
   textArea->clear();
}
}
</code>
</syntaxhighlight>
<tt>fileName.clear()</tt> sets the <tt>fileName</tt> QString to be empty to reflect the fact that this document does not yet have a presence on disc. <tt>textArea->clear()</tt> then clears the central text area using the same function that we connected the <tt>clear</tt> <tt>KAction</tt> to in tutorial 3.
<tt>fileName.clear()</tt> setzt den <tt>fileName</tt> QString auf leer um zu zeigen, dass dieses Dokument noch keine Präsenz auf der Festplatte hat. <tt>textArea->clear()</tt> leert dann das zentrale Textfeld unter Verwendung der gleichen Funktion mit der wir die <tt>clear</tt> <tt>KAction</tt> in Anleitung 3 verbunden haben.


===Saving a file===
===Speichern einer Datei===


====saveFileAs(QString)====
====saveFileAs(QString)====


Now we get onto our first file handling code. We're going to implement a function which will save the contents of the text area to the file name given as a parameter. KDE provides a class for safely saving a file called {{class|KSaveFile}} which is derived from Qt's {{qt|QFile}}.
Jetzt kommen wir zum ersten Datei-Handhabungs-Code. Wir werden eine Funktion einführen, die die Inhalte des Textfeldes in den Dateinamen, der als Parameter gegeben ist, speichert. KDE stellt die {{class|KSaveFile}} Klasse bereit, mit der man sicher Dateien speichern kann. Sie ist von Qt's {{qt|QFile}} abgeleitet.


The function's prototype is
 
<code cppqt>
Der Prototyp für unsere Funktion ist
<syntaxhighlight lang="cpp-qt">
void MainWindow::saveFileAs(const QString &outputFileName)
void MainWindow::saveFileAs(const QString &outputFileName)
</code>
</syntaxhighlight>
 
Wir erstellen dann unser <tt>KSaveFile</tt> Objekt und öffnen es mit
We then create our <tt>KSaveFile</tt> object and open it with
<syntaxhighlight lang="cpp-qt">
<code cppqt>
KSaveFile file(outputFileName);
KSaveFile file(outputFileName);
file.open();
file.open();
</code>
</syntaxhighlight>


Now that we have our file to write to, we need to format the text in the text area to a format which can be written to file. For this, we create a {{qt|QByteArray}} and fill it with the plain text version of whatever is in the text area:
 
<code cppqt>
Nun da wir unsere Datei zum Beschreiben haben, müssen wir den Text im Textfeld so formatieren, dass er in eine Datei geschrieben werden kann. Dazu erstellen wir ein {{qt|QByteArray}} und füllen es mit der einfachen Text Version von was auch immer im Textfeld ist:
<syntaxhighlight lang="cpp-qt">
QByteArray outputByteArray;
QByteArray outputByteArray;
outputByteArray.append(textArea->toPlainText());
outputByteArray.append(textArea->toPlainText());
</code>
</syntaxhighlight>
Now that we have our <tt>QByteArray</tt>, we use it to write to the file with <tt>KSaveFile::write()</tt>. If we were using a normal <tt>QFile</tt>, this would make the changes immediately. However, if a problem occurred partway through writing, the file would become corrupted. For this reason, <tt>KSaveFile</tt> works by first writing to a temporary file and then, when you call <tt>KSaveFile::finalize()</tt> the changes are made to the actual file.
Jetzt haben wir unser <tt>QByteArray</tt>, das wir dazu verwenden mit <tt>KSaveFile::write()</tt> in die Datei zu schreiben. Wenn wir ein normales <tt>QFile</tt> benutzen würden, würde dies die Änderungen sofort ausführen. Falls aber während dem Schreiben ein Fehler passieren würde, würde die Datei beschädigt werden. Darum speichert <tt>KSaveFile</tt> zuerst in eine temporäre Datei und dann, wenn man <tt>KSaveFile::finalize()</tt> aufruft, werden die Änderungen in die eigentliche Datei geschrieben.
<code cppqt>
<syntaxhighlight lang="cpp-qt">
file.write(outputByteArray);
file.write(outputByteArray);
file.finalize();
file.finalize();
file.close();
file.close();
</code>
</syntaxhighlight>
Finally, we set <tt>MainWindows</tt>'s <tt>fileName</tt> member to point to the file name we just saved to.
Schliesslich setzen wir <tt>MainWindows</tt>'s <tt>fileName</tt> Element dazu auf den Dateinamen zu zeigen, in den wir gerade geschrieben haben.
<code cppqt>
<syntaxhighlight lang="cpp-qt">
fileName = outputFileName;
fileName = outputFileName;
</code>
</syntaxhighlight>


====saveFileAs()====
====saveFileAs()====


This is the function that the <tt>saveAs</tt> slot is connected to. It simply calls the generic <tt>saveFileAs(QString)</tt> function and passes the file name returned by <tt>{{class|KFileDialog}}::[http://api.kde.org/4.0-api/kdelibs-apidocs/kio/html/classKFileDialog.html#8891356c249c5911e1ab15cc2739a89b getSaveFileName()]</tt>.
Dies ist die Funktion mit der der <tt>saveAs</tt> Slot verbunden ist. Sie ruft einfach eine normale <tt>saveFileAs(QString)</tt> Funktion auf und übergibt den Dateinamen der von <tt>{{class|KFileDialog}}::[http://api.kde.org/4.0-api/kdelibs-apidocs/kio/html/classKFileDialog.html#8891356c249c5911e1ab15cc2739a89b getSaveFileName()]</tt> zurückgegeben wird.


<code cppqt>
<syntaxhighlight lang="cpp-qt">
void MainWindow::saveFileAs()
void MainWindow::saveFileAs()
{
{
   saveFileAs(KFileDialog::getSaveFileName());
   saveFileAs(KFileDialog::getSaveFileName());
}
}
</code>
</syntaxhighlight>
 


This our first actual use of the KIO library. {{class|KFileDialog}} provides a number of static functions for displaying the common file dialog that is used by all KDE applications. Calling <tt>KFileDialog::getSaveFileName()</tt> will display a dialog where the user can select the name of the file to save to or choose a new name. The function returns the full file name, which we then pass to <tt>saveFileAs(QString)</tt>.
Dies ist unser erster eigentlicher Gebrauch der KIO Bibliothek. {{class|KFileDialog}} Stellt eine Anzahl statischer Funktionen bereit um den gemeinsamen Dateidialog, der von allen KDE Anwendungen genutzt wird, anzuzeigen.
<tt>KFileDialog::getSaveFileName()</tt> aufzurufen wird einen Dialog anzeigen wo der Benutzer den Namen der Datei eingeben kann in die er speichern will oder einen neuen Namen angeben. Diese Funktion gibt den vollständigen Dateinamen zurück, den wir dann <tt>saveFileAs(QString)</tt> übergeben.


====saveFile()====
====saveFile()====


<code cppqt>
<syntaxhighlight lang="cpp-qt">
void MainWindow::saveFile()
void MainWindow::saveFile()
{
{
Line 304: Line 313:
   }
   }
}
}
</code>
</syntaxhighlight>
 
Es gibt nichts neues oder aufregendes an dieser Funktion, nur die Logik zu entscheiden den Speicher-Dialog zu zeigen, oder nicht. Wenn <tt>fileName</tt> nicht leer ist, dann wird die Datei zu <tt>fileName</tt> gespeichert. Andernfalls wird der Dialog angezeigt damit der Benutzer einen Dateinamen bestimmen kann.


There's nothing exciting or new in this function, just the logic to decide whether or not to show the save dialog. If <tt>fileName</tt> is not empty, then the file is saved to <tt>fileName</tt>. But if it is, then the dialog is shown to allow the user to select a file name.
===Laden einer Datei===


===Loading a file===
Endlich werden wir in der Lage sein eine Datei zu öffnen. Der ganze Code hierfür ist in <tt>MainWindow::openFile()</tt> enthalten.


Finally, we get round to being able to load a file from disc. The code for this is all contained in <tt>MainWindow::openFile()</tt>.
Als erstes müssen wir den Benutzer nach dem Namen der Datei fragen, die er öffnen möchte. Dazu benutzen wir eine weitere <tt>KFileDialog</tt> Funktion diesmal <tt>getOpenFileName()</tt>:


First we must ask the user for the name of the file they wish to open. We do this using another one of the <tt>KFileDialog</tt> functions, this time <tt>getOpenFileName()</tt>:
<syntaxhighlight lang="cpp-qt">
<code cppqt>
QString fileNameFromDialog = KFileDialog::getOpenFileName();
QString fileNameFromDialog = KFileDialog::getOpenFileName();
</code>
</syntaxhighlight>


Then we use the KIO library to retrieve our file. This allows us to open the file with QFile even if it's stored in a remote location like an FTP site. We make the following call to {{class|NetAccess}}'s <tt>download()</tt> function
Dann nutzen wir die KIO Bibliothek, um unsere Datei aufzurufen. Das ermöglicht es uns die Datei mit QFile zu öffnen, selbst wenn sie sich auf einem externen Speicherort befindet, wie auf einer FTP-Seite. Wir machen den folgenden Aufruf an die  {{class|NetAccess}} <tt>download()</tt> Funktion:
<code cppqt>
 
<syntaxhighlight lang="cpp-qt">
KIO::NetAccess::download(fileNameFromDialog, tmpFile, this)
KIO::NetAccess::download(fileNameFromDialog, tmpFile, this)
</code>
</syntaxhighlight>
The first argument is the name of the file you wish to download. The second is a QString which, after the download is complete, will contain the location of the temporary copy of the file. It is this <tt>tmpFile</tt> we will work with from now on.
 
Diese Funktion speichert die Datei temporär auf der Festplatte. Das erste Argument ist der Name der Datei, die man öffnen möchte. Das zweite ist ein QString der, nachdem der Download abgeschlossen ist den Speicherort der temporären Datei enthalten wird. Es ist mit diesem <tt>tmpFile</tt>, mit dem wir von nun an arbeiten werden.
 


The function returns <tt>true</tt> or <tt>false</tt> depending on whether the transfer was successful. If it failed, we display a message box giving the error:
Die Funktion gibt <tt>true</tt> oder <tt>false</tt> zurück, je nachdem ob die Übertragung erfolgreich war oder nicht. Falls sie fehlgeschlagen ist, wird eine Fehlermeldung angezeigt:
<code cppqt>
 
<syntaxhighlight lang="cpp-qt">
KMessageBox::error(this, KIO::NetAccess::lastErrorString());
KMessageBox::error(this, KIO::NetAccess::lastErrorString());
</code>
</syntaxhighlight>
 
Ansonsten fahren wir fort, die Datei zu öffnen.


Otherwise, we continue with opening the file.
Wir erstellen ein QFile indem wir die temporäre Datei die durch <tt>NetAccess::download()</tt> erzeugt wurde ihrem Konstruktor übergeben und dann in schreibgeschütztem Modus öffnen:


We create a QFile by passing the temporary file created by <tt>NetAccess::download()</tt> to its constructor and then open it in read-only mode
<syntaxhighlight lang="cpp-qt">
<code cppqt>
QFile file(tmpFile);
QFile file(tmpFile);
file.open(QIODevice::ReadOnly);
file.open(QIODevice::ReadOnly);
</code>
</syntaxhighlight>


In order to display the contents of the file, we must use a {{class|QTextStream}}. We create one by passing the contents of our file to its constructor and then call QFile's <tt>readAll()</tt> function to get the text from the file. This is then passed to the <tt>setPlainText()</tt> function of our text area.
Um den Inhalt der Datei anzuzeigen, müssen wir Gebrauch von einem {{class|QTextStream}} machen. Wir erstellen einen, indem wir den Inhalt unserer Datei seinem Konstruktor übergeben und dann QFile's <tt>readAll()</tt> Funktion aufrufen um den Text von der Datei zu erhalten. Dieser wird dann zu der <tt>setPlainText()</tt> Funktion unseres Textfelds übergeben:


<code cppqt>
<syntaxhighlight lang="cpp-qt">
textArea->setPlainText(QTextStream(&file).readAll());
textArea->setPlainText(QTextStream(&file).readAll());
</code>
</syntaxhighlight>
 
Wir speichern dann den Pfad der Datei, die wir gerade geöffnet haben:


We then store the path of the file we just opened:
<syntaxhighlight lang="cpp-qt">
<code cppqt>
fileName = fileNameFromDialog;
fileName = fileNameFromDialog;
</code>
</syntaxhighlight>
and finally, we remove the temporary file that was created by <tt>NetAccess::download()</tt>:
 
<code cppqt>
Und schliesslich entfernen wir die temporäre Datei, die durch <tt>NetAccess::download()</tt> erstellt wurde:
 
<syntaxhighlight lang="cpp-qt">
KIO::NetAccess::removeTempFile(tmpFile);
KIO::NetAccess::removeTempFile(tmpFile);
</code>
</syntaxhighlight>


==Make, Install And Run==
==Erzeugen, Installieren und Ausführen==


===CMakeLists.txt===
===CMakeLists.txt===
<code ini n>
<syntaxhighlight lang="ini" line>
project(tutorial4)
project(tutorial4)
   
   
Line 373: Line 391:
install(FILES tutorial4ui.rc  
install(FILES tutorial4ui.rc  
         DESTINATION ${DATA_INSTALL_DIR}/tutorial4)
         DESTINATION ${DATA_INSTALL_DIR}/tutorial4)
</code>
</syntaxhighlight>
Since we are now using the KIO library, we must tell CMake to link against it. We do this by passing <tt>${KDE4_KIO_LIBS}</tt> to the <tt>target_link_libraries()</tt> function.
Da wir nun die KIO Bibliothek verwenden, müssen wir CMake mitteilen es einzubinden. Wir machen das indem wir <tt>${KDE4_KIO_LIBS}</tt> der <tt>target_link_libraries()</tt> Funktion übergeben.


With this file, the tutorial can built and run in the same way as tutorial 3. For more information, see tutorial 3.
Mit dieser Datei kann die Anleitung auf die selbe Weise erzeugt und ausgeführt werden wie in Anleitung 3. Für weitere Informationen, siehe [[Development/Tutorials/Using KActions (de)|Anleitung 3]].


  mkdir build && cd build
  mkdir build && cd build
Line 383: Line 401:
  $HOME/bin/tutorial4
  $HOME/bin/tutorial4


==Moving On==
==Weiter geht's==
Now you can move on to the [[Development/Tutorials/KCmdLineArgs|KCmdLineArgs]] tutorial.
Jetzt können sie mit dem Kapitel [[Development/Tutorials/KCmdLineArgs (de)|KCmdLineArgs]] forfahren.


[[Category:C++]]
[[Category:C++]]

Latest revision as of 15:44, 14 July 2012


Laden und Speichern von Dateien
Anleitungsserie   Anleitung für Anfänger
Voriges Kapitel   Anleitung 3 - KActions benutzen
Nächstes Kapitel   Anleitung 5 - KCmdLineArgs benutzen
Weiterführende Texte   KIO::NetAccess QFile
Navigation   Deutsche Startseite

Zusammenfassung

In diesem Kapitel werden Sie lernen, wie man grundsätzliche Datei-Aktionen wie Laden und Speichern mithilfe der KIO Bibliothek einbindet.

KDE stellt eine Anzahl von Klassen bereit um das Arbeiten mit Dateien für die Entwickler deutlich zu vereinfachen. Die KIO Bibliothek ermöglicht es Dateien auf einfache Weise über Netzwerk-transparente Protokolle anzusteuern und stellt auch Standard Dateidialoge bereit.

Der Code

main.cpp

#include <KApplication>
#include <KAboutData>
#include <KCmdLineArgs>
 
#include "mainwindow.h"
 
int main (int argc, char *argv[])
{
  KAboutData aboutData( "tutorial4", "tutorial4",
      ki18n("Tutorial 4"), "1.0",
      ki18n("A simple text area which can load and save."),
      KAboutData::License_GPL,
      ki18n("Copyright (c) 2007 Developer") );
  KCmdLineArgs::init( argc, argv, &aboutData );
  KApplication app;
 
  MainWindow* window = new MainWindow();
  window->show();
  return app.exec();
}

main.cpp hat sich seit der dritten Anleitung nicht verändert, ausser das jeder Bezug zu 'tutorial 3' zu 'tutorial 4' geändert wurde.

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <KXmlGuiWindow>
#include <KTextEdit>

class MainWindow : public KXmlGuiWindow
{
  Q_OBJECT //neu seit Anleitung 3
  
  public:
    MainWindow(QWidget *parent=0);
  
  private:
    KTextEdit* textArea;
    void setupActions();
    QString fileName; //neu

  private slots: //neu
    void newFile(); //neu
    void openFile(); //neu
    void saveFile(); //neu
    void saveFileAs(); //neu
    void saveFileAs(const QString &outputFileName); //neu
};

#endif

Da wir unserem Programm die Fähigkeit geben wollen, Dateien zu laden und zu speichern müssen wir Funktionen hinzufügen, die diese Arbeit erledigen werden. Da die Funktionen durch Qt's signal/slot-Mechanismus aufgerufen werden, müssen wir definieren, dass diese Funktionen Slots sind, wie wir dies auf Zeile 19 machen. Da wir Slots in diesem Header-File benutzen, müssen wir auch das Q_OBJECT Makro hinzufügen.

Wir werden auch den Dateinamen der momentan geöffneten Datei verfügbar haben wollen, also definieren wir einen QString fileName.

mainwindow.cpp

#include "mainwindow.h"

#include <KApplication>
#include <KAction>
#include <KLocale>
#include <KActionCollection>
#include <KStandardAction>
#include <KFileDialog> //neu
#include <KMessageBox> //neu
#include <KIO/NetAccess> //neu
#include <KSaveFile> //neu
#include <QTextStream> //neu
 
MainWindow::MainWindow(QWidget *parent)
    : KXmlGuiWindow(parent),
      fileName(QString()) //neu
{
  textArea = new KTextEdit;
  setCentralWidget(textArea);
 
  setupActions();
}
 
void MainWindow::setupActions()
{
  KAction* clearAction = new KAction(this);
  clearAction->setText(i18n("Clear"));
  clearAction->setIcon(KIcon("document-new"));
  clearAction->setShortcut(Qt::CTRL + Qt::Key_W);
  actionCollection()->addAction("clear", clearAction);
  connect(clearAction, SIGNAL(triggered(bool)),
          textArea, SLOT(clear()));
 
  KStandardAction::quit(kapp, SLOT(quit()),
                        actionCollection());
 
  KStandardAction::open(this, SLOT(openFile()),
                        actionCollection()); //neu
 
  KStandardAction::save(this, SLOT(saveFile()),
                        actionCollection()); //neu
 
  KStandardAction::saveAs(this, SLOT(saveFileAs()),
                        actionCollection()); //neu
 
  KStandardAction::openNew(this, SLOT(newFile()),
                        actionCollection()); //neu
 
  setupGUI();
}

//Neu ab hier

void MainWindow::newFile()
{
  fileName.clear();
  textArea->clear();
}

void MainWindow::saveFileAs(const QString &outputFileName)
{
  KSaveFile file(outputFileName);
  file.open();
  
  QByteArray outputByteArray;
  outputByteArray.append(textArea->toPlainText());
  file.write(outputByteArray);
  file.finalize();
  file.close();
  
  fileName = outputFileName;
}

void MainWindow::saveFileAs()
{
  saveFileAs(KFileDialog::getSaveFileName());
}

void MainWindow::saveFile()
{
  if(!fileName.isEmpty())
  {
    saveFileAs(fileName);
  }
  else
  {
    saveFileAs();
  }
}

void MainWindow::openFile()
{
  QString fileNameFromDialog = KFileDialog::getOpenFileName();

  QString tmpFile;
  if(KIO::NetAccess::download(fileNameFromDialog, tmpFile, 
         this))
  {
    QFile file(tmpFile);
    file.open(QIODevice::ReadOnly);
    textArea->setPlainText(QTextStream(&file).readAll());
    fileName = fileNameFromDialog;

    KIO::NetAccess::removeTempFile(tmpFile);
  }
  else
  {
    KMessageBox::error(this, 
        KIO::NetAccess::lastErrorString());
  }
}

tutorial4ui.rc

<?xml version="1.0" encoding="UTF-8"?>
<gui name="tutorial4"
     version="1"
     xmlns="http://www.kde.org/standards/kxmlgui/1.0"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://www.kde.org/standards/kxmlgui/1.0
                         http://www.kde.org/standards/kxmlgui/1.0/kxmlgui.xsd" >

  <MenuBar>
    <Menu name="file" >
      <Action name="clear" />
    </Menu>
  </MenuBar>

  <ToolBar name="mainToolBar" >
    <text>Main Toolbar</text>
    <Action name="clear" />
  </ToolBar>

</gui>

Dies ist identisch mit tutorial3ui.rc aus Anleitung 3 ausser dass name zu 'tutorial4' geändert wurde. Wir müssen keine Informationen über irgendeine der KStandardActions hinzuzufügen da die Platzierung dieser Aktionen automatisch durch KDE erfolgt.

Erklärung

Nun kommen wir zum Code, der das Laden und Speichern erledigen wird. Das wird alles in mainwindow.cpp passieren.

Als erstes fügen wir

fileName(QString())

der MainWindow Konstruktor-Liste auf Zeile 16 hinzu. Das stellt sicher, dass fileName von Anfang an leer ist.

Hinzufügen der Aktionen

Als nächstes werden wir das äusserliche Interface für den Benutzer bereitstellen, so dass er der Anwendung mitteilen kann zu laden und zu speichern. Wie mit der quit Aktion in Anleitung 3 werden wir KStandardActions verwenden. Auf Zeilen 37 bis 47 werden wir die Aktionen auf die selbe Weise hinzufügen wie für die quit Aktion. Für jedes einzelne werden wir es mit dem richtigen Slot verbinden den wir in der Header Datei definiert haben.

Erstellen eines neuen Dokuments

Die erste Funktion die wir erstellen ist newFile().

void MainWindow::newFile()
{
  fileName.clear();
  textArea->clear();
}

fileName.clear() setzt den fileName QString auf leer um zu zeigen, dass dieses Dokument noch keine Präsenz auf der Festplatte hat. textArea->clear() leert dann das zentrale Textfeld unter Verwendung der gleichen Funktion mit der wir die clear KAction in Anleitung 3 verbunden haben.

Speichern einer Datei

saveFileAs(QString)

Jetzt kommen wir zum ersten Datei-Handhabungs-Code. Wir werden eine Funktion einführen, die die Inhalte des Textfeldes in den Dateinamen, der als Parameter gegeben ist, speichert. KDE stellt die KSaveFile Klasse bereit, mit der man sicher Dateien speichern kann. Sie ist von Qt's QFile abgeleitet.


Der Prototyp für unsere Funktion ist

void MainWindow::saveFileAs(const QString &outputFileName)

Wir erstellen dann unser KSaveFile Objekt und öffnen es mit

KSaveFile file(outputFileName);
file.open();


Nun da wir unsere Datei zum Beschreiben haben, müssen wir den Text im Textfeld so formatieren, dass er in eine Datei geschrieben werden kann. Dazu erstellen wir ein QByteArray und füllen es mit der einfachen Text Version von was auch immer im Textfeld ist:

QByteArray outputByteArray;
outputByteArray.append(textArea->toPlainText());

Jetzt haben wir unser QByteArray, das wir dazu verwenden mit KSaveFile::write() in die Datei zu schreiben. Wenn wir ein normales QFile benutzen würden, würde dies die Änderungen sofort ausführen. Falls aber während dem Schreiben ein Fehler passieren würde, würde die Datei beschädigt werden. Darum speichert KSaveFile zuerst in eine temporäre Datei und dann, wenn man KSaveFile::finalize() aufruft, werden die Änderungen in die eigentliche Datei geschrieben.

file.write(outputByteArray);
file.finalize();
file.close();

Schliesslich setzen wir MainWindows's fileName Element dazu auf den Dateinamen zu zeigen, in den wir gerade geschrieben haben.

fileName = outputFileName;

saveFileAs()

Dies ist die Funktion mit der der saveAs Slot verbunden ist. Sie ruft einfach eine normale saveFileAs(QString) Funktion auf und übergibt den Dateinamen der von KFileDialog::getSaveFileName() zurückgegeben wird.

void MainWindow::saveFileAs()
{
  saveFileAs(KFileDialog::getSaveFileName());
}


Dies ist unser erster eigentlicher Gebrauch der KIO Bibliothek. KFileDialog Stellt eine Anzahl statischer Funktionen bereit um den gemeinsamen Dateidialog, der von allen KDE Anwendungen genutzt wird, anzuzeigen. KFileDialog::getSaveFileName() aufzurufen wird einen Dialog anzeigen wo der Benutzer den Namen der Datei eingeben kann in die er speichern will oder einen neuen Namen angeben. Diese Funktion gibt den vollständigen Dateinamen zurück, den wir dann saveFileAs(QString) übergeben.

saveFile()

void MainWindow::saveFile()
{
  if(!fileName.isEmpty())
  {
    saveFileAs(fileName);
  }
  else
  {
    saveFileAs();
  }
}

Es gibt nichts neues oder aufregendes an dieser Funktion, nur die Logik zu entscheiden den Speicher-Dialog zu zeigen, oder nicht. Wenn fileName nicht leer ist, dann wird die Datei zu fileName gespeichert. Andernfalls wird der Dialog angezeigt damit der Benutzer einen Dateinamen bestimmen kann.

Laden einer Datei

Endlich werden wir in der Lage sein eine Datei zu öffnen. Der ganze Code hierfür ist in MainWindow::openFile() enthalten.

Als erstes müssen wir den Benutzer nach dem Namen der Datei fragen, die er öffnen möchte. Dazu benutzen wir eine weitere KFileDialog Funktion diesmal getOpenFileName():

QString fileNameFromDialog = KFileDialog::getOpenFileName();

Dann nutzen wir die KIO Bibliothek, um unsere Datei aufzurufen. Das ermöglicht es uns die Datei mit QFile zu öffnen, selbst wenn sie sich auf einem externen Speicherort befindet, wie auf einer FTP-Seite. Wir machen den folgenden Aufruf an die NetAccess download() Funktion:

KIO::NetAccess::download(fileNameFromDialog, tmpFile, this)

Diese Funktion speichert die Datei temporär auf der Festplatte. Das erste Argument ist der Name der Datei, die man öffnen möchte. Das zweite ist ein QString der, nachdem der Download abgeschlossen ist den Speicherort der temporären Datei enthalten wird. Es ist mit diesem tmpFile, mit dem wir von nun an arbeiten werden.


Die Funktion gibt true oder false zurück, je nachdem ob die Übertragung erfolgreich war oder nicht. Falls sie fehlgeschlagen ist, wird eine Fehlermeldung angezeigt:

KMessageBox::error(this, KIO::NetAccess::lastErrorString());

Ansonsten fahren wir fort, die Datei zu öffnen.

Wir erstellen ein QFile indem wir die temporäre Datei die durch NetAccess::download() erzeugt wurde ihrem Konstruktor übergeben und dann in schreibgeschütztem Modus öffnen:

QFile file(tmpFile);
file.open(QIODevice::ReadOnly);

Um den Inhalt der Datei anzuzeigen, müssen wir Gebrauch von einem QTextStream machen. Wir erstellen einen, indem wir den Inhalt unserer Datei seinem Konstruktor übergeben und dann QFile's readAll() Funktion aufrufen um den Text von der Datei zu erhalten. Dieser wird dann zu der setPlainText() Funktion unseres Textfelds übergeben:

textArea->setPlainText(QTextStream(&file).readAll());

Wir speichern dann den Pfad der Datei, die wir gerade geöffnet haben:

fileName = fileNameFromDialog;

Und schliesslich entfernen wir die temporäre Datei, die durch NetAccess::download() erstellt wurde:

KIO::NetAccess::removeTempFile(tmpFile);

Erzeugen, Installieren und Ausführen

CMakeLists.txt

project(tutorial4)
 
find_package(KDE4 REQUIRED)
include_directories(${KDE4_INCLUDES})
 
set(tutorial4_SRCS 
  main.cpp
  mainwindow.cpp
)
 
kde4_add_executable(tutorial4 ${tutorial4_SRCS})
 
target_link_libraries(tutorial4 ${KDE4_KDEUI_LIBS} 
                                ${KDE4_KIO_LIBS})
 
install(TARGETS tutorial4 DESTINATION ${BIN_INSTALL_DIR})
install(FILES tutorial4ui.rc 
        DESTINATION ${DATA_INSTALL_DIR}/tutorial4)

Da wir nun die KIO Bibliothek verwenden, müssen wir CMake mitteilen es einzubinden. Wir machen das indem wir ${KDE4_KIO_LIBS} der target_link_libraries() Funktion übergeben.

Mit dieser Datei kann die Anleitung auf die selbe Weise erzeugt und ausgeführt werden wie in Anleitung 3. Für weitere Informationen, siehe Anleitung 3.

mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=$HOME
make install
$HOME/bin/tutorial4

Weiter geht's

Jetzt können sie mit dem Kapitel KCmdLineArgs forfahren.