Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
QML Qt / Qml / 4_Текстовий редактор в QML.doc
Скачиваний:
82
Добавлен:
28.03.2016
Размер:
504.32 Кб
Скачать

Регистрация класса в qml

В dialogPlugin.h:

#include <QtDeclarative/QDeclarativeExtensionPlugin>

class DialogPlugin : public QDeclarativeExtensionPlugin

{

Q_OBJECT

public:

void registerTypes(const char *uri);

};

Our plugin class, DialogPlugin is a subclass of QDeclarativeExtensionPlugin. We need to implement the inherited function, registerTypes(). The dialogPlugin.cpp file looks like this:

DialogPlugin.cpp:

#include "dialogPlugin.h"

#include "directory.h"

#include "file.h"

#include <QtDeclarative/qdeclarative.h>

void DialogPlugin::registerTypes(const char *uri){

qmlRegisterType<Directory>(uri, 1, 0, "Directory");

qmlRegisterType<File>(uri, 1, 0,"File");

}

Q_EXPORT_PLUGIN2(FileDialog, DialogPlugin);

The registerTypes() function registers our File and Directory classes into QML. This function needs the class name for its template, a major version number, a minor version number, and a name for our classes.

We need to export the plugin using the Q_EXPORT_PLUGIN2 macro. Note that in our dialogPlugin.h file, we have the Q_OBJECT macro at the top of our class. As well, we need to run qmake on the project file to generate the necessary meta-object code.

Создание свойств QML в классе C++

We can create QML elements and properties using C++ and Qt's Meta-Object System. We can implement properties using slots and signals, making Qt aware of these properties. These properties can then be used in QML.

For the text editor, we need to be able to load and save files. Typically, these features are contained in a file dialog. Fortunately, we can use QDir, QFile, and QTextStream to implement directory reading and input/output streams.

class Directory : public QObject{

Q_OBJECT

Q_PROPERTY(int filesCount READ filesCount CONSTANT)

Q_PROPERTY(QString filename READ filename WRITE setFilename NOTIFY filenameChanged)

Q_PROPERTY(QString fileContent READ fileContent WRITE setFileContent NOTIFY fileContentChanged)

Q_PROPERTY(QDeclarativeListProperty<File> files READ files CONSTANT )

...

The Directory class uses Qt's Meta-Object System to register properties it needs to accomplish file handling. The Directory class is exported as a plugin and is useable in QML as the Directory element. Each of the listed properties using the Q_PROPERTY macro is a QML property.

The Q_PROPERTY declares a property as well as its read and write functions into Qt's Meta-Object System. For example, the filename property, of type QString, is readable using the filename() function and writable using the function setFilename(). Additionally, there is a signal associated to the filename property called filenameChanged(), which is emitted whenever the property changes. The read and write functions are declared as public in the header file.

Similarly, we have the other properties declared according to their uses. The filesCount property indicates the number of files in a directory. The filename property is set to the currently selected file's name and the loaded/saved file content is stored in fileContent property.

Q_PROPERTY(QDeclarativeListProperty<File> files READ files CONSTANT )

The files list property is a list of all the filtered files in a directory. The Directory class is implemented to filter out invalid text files; only files with a .txt extension are valid. Further, QLists can be used in QML files by declaring them as a QDeclarativeListProperty in C++. The templated object needs to inherit from a QObject, therefore, the File class must also inherit from QObject. In the Directory class, the list of File objects is stored in a QList called m_fileList.

class File : public QObject{

Q_OBJECT

Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)

...

};

The properties can then be used in QML as part of the Directory element's properties. Note that we do not have to create an identifier id property in our C++ code.

Directory{

id: directory

filesCount

filename

fileContent

files

files[0].name

}

Because QML uses Javascript's syntax and structure, we can iterate through the list of files and retrieve its properties. To retrieve the first file's name property, we can call files[0].name.

Regular C++ functions are also accessible from QML. The file loading and saving functions are implemented in C++ and declared using the Q_INVOKABLE macro. Alternatively, we can declare the functions as a slot and the functions will be accessible from QML.

В Directory.h:

Q_INVOKABLE void saveFile();

Q_INVOKABLE void loadFile();

The Directory class also has to notify other objects whenever the directory contents change. This feature is performed using a signal. As previously mentioned, QML signals have a corresponding handler with their names prepended with on. The signal is called directoryChanged and it is emitted whenever there is a directory refresh. The refresh simply reloads the directory contents and updates the list of valid files in the directory. QML items can then be notified by attaching an action to the onDirectoryChanged signal handler.

The list properties need to be explored further. This is because list properties use callbacks to access and modify the list contents. The list property is of type QDeclarativeListProperty<File>. Whenever the list is accessed, the accessor function needs to return a QDeclarativeListProperty<File>. The template type, File, needs to be a QObject derivative. Further, to create the QDeclarativeListProperty, the list's accessor and modifiers need to be passed to the constructor as function pointers. The list, a QList in our case, also needs to be a list of File pointers.

The constructor of QDeclarativeListProperty constructor and the Directory implementation:

QDeclarativeListProperty ( QObject * object, void * data, AppendFunction append, CountFunction count = 0, AtFunction at = 0, ClearFunction clear = 0 )

QDeclarativeListProperty<File>( this, &m_fileList, &appendFiles, &filesSize, &fileAt, &clearFilesPtr );

The constructor passes pointers to functions that will append the list, count the list, retrieve the item using an index, and empty the list. Only the append function is mandatory. Note that the function pointers must match the definition of AppendFunction, CountFunction, AtFunction, or ClearFunction.

void appendFiles(QDeclarativeListProperty<File> * property, File * file)

File* fileAt(QDeclarativeListProperty<File> * property, int index)

int filesSize(QDeclarativeListProperty<File> * property)

void clearFilesPtr(QDeclarativeListProperty<File> *property)

To simplify our file dialog, the Directory class filters out invalid text files, which are files that do not have a .txt extension. If a file name doesn't have the .txt extension, then it won't be seen in our file dialog. Also, the implementation makes sure that saved files have a .txt extension in the file name. Directory uses QTextStream to read the file and to output the file contents to a file.

With our Directory element, we can retrieve the files as a list, know how many text files is in the application directory, get the file's name and content as a string, and be notified whenever there are changes in the directory contents.

To build the plugin, run qmake on the filedialog.pro project file, then run make to build and transfer the plugin to the plugins directory.

Importing a Plugin in QML

The qmlviewer tool imports files that are in the same directory as the application. We can also create a qmldir file containing the locations of QML files we wish to import. The qmldir file can also store locations of plugins and other resources.

В qmldir:

Button ./Button.qml

FileDialog ./FileDialog.qml

TextArea ./TextArea.qml

TextEditor ./TextEditor.qml

EditMenu ./EditMenu.qml

plugin FileDialog plugins

The plugin we just created is called FileDialog, as indicated by the TARGET field in the project file. The compiled plugin is in the plugins directory.

Integrating a File Dialog into the File Menu

Our FileMenu needs to display the FileDialog element, containing a list of the text files in a directory thus allowing the user to select the file by clicking on the list. We also need to assign the save, load, and new buttons to their respective actions. The FileMenu contains an editable text input to allow the user to type a file name using the keyboard.

The Directory element is used in the FileMenu.qml file and it notifies the FileDialog element that the directory refreshed its contents. This notification is performed in the signal handler, onDirectoryChanged.

В FileMenu.qml:

Directory{

id:directory

filename: textInput.text

onDirectoryChanged: fileDialog.notifyRefresh()

}

Keeping with the simplicity of our application, the file dialog will always be visible and will not display invalid text files, which do not have a .txt extension to their filenames.

В FileDialog.qml:

signal notifyRefresh()

onNotifyRefresh: dirView.model = directory.files

The FileDialog element will display the contents of a directory by reading its list property called files. The files are used as the model of a GridView element, which displays data items in a grid according to a delegate. The delegate handles the appearance of the model and our file dialog will simply create a grid with text centered in the middle. Clicking on the file name will result in the appearance of a rectangle to highlight the file name. The FileDialog is notified whenever the notifyRefresh signal is emitted, reloading the files in the directory.

В FileMenu.qml:

Button{

id: newButton

label: "New"

onButtonClick:{

textArea.textContent = ""

}

}

Button{

id: loadButton

label: "Load"

onButtonClick:{

directory.filename = textInput.text

directory.loadFile()

textArea.textContent = directory.fileContent

}

}

Button{

id: saveButton

label: "Save"

onButtonClick:{

directory.fileContent = textArea.textContent

directory.filename = textInput.text

directory.saveFile()

}

}

Button{

id: exitButton

label: "Exit"

onButtonClick:{

Qt.quit()

}

}

Our FileMenu can now connect to their respective actions. The saveButton will transfer the text from the TextEdit onto the directory's fileContent property, then copy its file name from the editable text input. Finally, the button calls the saveFile() function, saving the file. The loadButton has a similar execution. Also, the New action will empty the contents of the TextEdit.

Further, the EditMenu buttons are connected to the TextEdit functions to copy, paste, and select all the text in the text editor.

Text Editor Completion

The application can function as a simple text editor, able to accept text and save the text into a file. The text editor can also load from a file and perform text manipulation.

Running the Text Editor

We need to compile the file dialog C++ plugin before the text editor can run. To compile, enter the gsQml directory, then run qmake and compile using make or nmake, depending on your platform. To run, launch qmlviewer and open the texteditor.qml file.

The source code is in the examples/tutorials/gettingStarted/gsQml directory.

© 2008-2011 Nokia Corporation и/или её дочерние компании. Nokia, Qt и их соответствующие логотипы являются торговыми марками Nokia Corporation в Финляндии и/или других странах.

Все остальные торговые марки являются собственностью их владельцев. Политика конфиденциальности

Лицензиаты, имеющие действительные коммерческие лицензии Qt, могут использовать этот документ в соответствии с соглашениями коммерческой лицензии Qt, поставляемой с программным обеспечением, либо, альтернативно, в соответствии с условиями, содержащимися в письменном соглашении между вами и Nokia.

Кроме того, этот документ может быть использован в соответствии с условиями GNU Free Documentation License version 1.3, опубликованной фондом Free Software Foundation.