diff --git a/Nim/Docs/NimQml.txt b/Nim/Docs/NimQml.txt index 6734b56..5601483 100644 --- a/Nim/Docs/NimQml.txt +++ b/Nim/Docs/NimQml.txt @@ -1,5 +1,6 @@ :Authors: Filippo Cucchetto + Will Szumski :Version: 0.1.0 :Date: 2015/01/02 @@ -57,7 +58,7 @@ or by manually copying the library in your system lib directory :: sudo cp build/dir/path/DOtherSide/libDOtherSide.so /usr/lib -First example: HelloWorld +Example 1: HelloWorld ---------- As usual lets start with an HelloWorld example. Most of the NimQml projects are made by one or more nim and qml @@ -81,7 +82,7 @@ The following example shows the basic steps of each NimQml app 3. Call the ``exec`` proc of the QApplication instance for starting the Qt event loop -Second example: exposing data to Qml +Example 2: exposing data to Qml ------------------------------------ The previous example shown you how to create a simple application window and how to startup the Qt event loop. @@ -113,16 +114,82 @@ At the time of writing the QVariant class support the following types: * bool * QObject derived classes -Third example: exposing complex data and procedures to Qml +Example 3: exposing complex data and procedures to Qml ---------------------------------------------------------- As seen by the second example simple data is fine. However most applications need to expose complex data, functions and update the view when something change in the data layer. -This is achieved by creating object that derives from QObject. +This is achieved by creating an object that derives from QObject. A QObject is made of : -1. ``Slots``: slots are function callable from the Qml engine -2. ``Signals``: signals allow the sending of events +1. ``Slots``: slots are function that could both be called from the qml engine and connected to Qt signals +2. ``Signals``: signals allow the sending of events and be connected to slots 3. ``Properties``: properties allows the passing of data to the Qml view and make it aware of changes in the data layer +A QObject property is made of three things: +* a read slot, a method that return the current value of the property +* a write slot, a method that set the value of the property +* a notify signal for telling that the current value of the property has been changed + +We'll start by looking at the main.nim file + +``Examples/SlotsAndProperties/main.nim`` + +.. code-block:: nim + :file: ../Examples/SlotsAndProperties/main.nim + +Here's nothing special happen except: +1. The creation of Contact object +2. The injection of the Contact object to the Qml root context + using the ``setContextProperty`` as seen in the previous + example + +The Qml file is as follow: + +``Examples/SlotsAndProperties/main.qml`` + +.. code-block:: qml + :file: ../Examples/SlotsAndProperties/main.qml + +The qml is made by a Label, a TextInput and a button. +The label display the contact name and automatically udpates when +the concat name changes. + +The button update the contact name with the TextInput text when clicked. + +So where's the magic? + +The magic is in the Contact.nim file + +``Examples/SlotsAndProperties/Contact.nim`` + +.. code-block:: nim + :file: ../Examples/SlotsAndProperties/Contact.nim + + +What First we declare a QObject subclass and provide a simple +new method where: +1. invoke the ``create()`` procedure. This invoke the C++ bridge and allocate +a QObject instance +2. register a slot ``getName`` for reading the Contact name field +3. register a slot `` setName`` for writing the Contact name +4. register a signal ``nameChanged`` for notify the contact name changes +5. register a property called ``name`` of type ``QString`` with the given + read, write slots and notify signal + +The two slots method implementation are trivial and consist in standard +nim methods. However ``setName`` slot method shows how to emit a signal +by using the ``emit`` method. + +The last thing to condider is the override of the ``onSlotCalled`` method. +This method is called by the NimQml library when an invokation occur from +the Qml side for one of the QObject slot. +The usual implementation for the onSlotCalled method consists in a +switch statement that forward the arguments to the correct slot. +If the invoked slot has a return value this is always in the index position +0 of the args array. + + +Example 4: QtObject macro + diff --git a/Nim/Examples/CMakeLists.txt b/Nim/Examples/CMakeLists.txt index 209534a..fec58ad 100644 --- a/Nim/Examples/CMakeLists.txt +++ b/Nim/Examples/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(HelloWorld) add_subdirectory(SimpleData) -add_subdirectory(Simple) \ No newline at end of file +add_subdirectory(Simple) +add_subdirectory(SlotsAndProperties) \ No newline at end of file diff --git a/Nim/Examples/SlotsAndProperties/CMakeLists.txt b/Nim/Examples/SlotsAndProperties/CMakeLists.txt new file mode 100644 index 0000000..5b6ed7b --- /dev/null +++ b/Nim/Examples/SlotsAndProperties/CMakeLists.txt @@ -0,0 +1,2 @@ +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/main.qml DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) +add_nim_executable(TARGET SlotsAndProperties SOURCES main.nim PATHS ../../NimQml) \ No newline at end of file diff --git a/Nim/Examples/SlotsAndProperties/Contact.nim b/Nim/Examples/SlotsAndProperties/Contact.nim new file mode 100644 index 0000000..1f04a04 --- /dev/null +++ b/Nim/Examples/SlotsAndProperties/Contact.nim @@ -0,0 +1,31 @@ +import NimQml + +type Contact = ref object of QObject + m_name: string + +template newContact*(): Contact = + var result = Contact(m_name: "initialName") + result.create() + result.m_name = "InitialName" + result.registerSlot("getName", [QMetaType.QString]) + result.registerSlot("setName", [QMetaType.Void, QMetaType.QString]) + result.registerSignal("nameChanged", [QMetaType.Void]) + result.registerProperty("name", QMetaType.QString, "getName", "setName", "nameChanged") + result + +method getName*(self: Contact): string = + result = self.m_name + +method setName*(self: Contact, name: string) = + if self.m_name != name: + self.m_name = name + self.emit("nameChanged") + +method onSlotCalled(self: Contact, slotName: string, args: openarray[QVariant]) = + case slotName: + of "getName": + args[0].stringVal = self.getName() + of "setName": + self.setName(args[1].stringVal) + else: + discard() \ No newline at end of file diff --git a/Nim/Examples/SlotsAndProperties/main.nim b/Nim/Examples/SlotsAndProperties/main.nim new file mode 100644 index 0000000..3e85e9e --- /dev/null +++ b/Nim/Examples/SlotsAndProperties/main.nim @@ -0,0 +1,27 @@ +import NimQml +import Contact + +proc mainProc() = + var app: QApplication + app.create() + defer: app.delete() + + var contact = newContact() + defer: contact.delete() + + var engine: QQmlApplicationEngine + engine.create() + defer: engine.delete() + + var variant: QVariant + variant.create(contact) + defer: variant.delete() + + var rootContext: QQmlContext = engine.rootContext() + rootContext.setContextProperty("contact", variant) + engine.load("main.qml") + app.exec() + +when isMainModule: + mainProc() + diff --git a/Nim/Examples/SlotsAndProperties/main.qml b/Nim/Examples/SlotsAndProperties/main.qml new file mode 100644 index 0000000..f21c4be --- /dev/null +++ b/Nim/Examples/SlotsAndProperties/main.qml @@ -0,0 +1,33 @@ +import QtQuick 2.2 +import QtQuick.Controls 1.2 +import QtQuick.Layouts 1.1 +import QtQuick.Window 2.1 + +ApplicationWindow +{ + width: 400 + height: 300 + + Component.onCompleted: visible = true + + ColumnLayout + { + anchors.fill: parent + + Label + { + text: "Current name is:" + contact.name + } + + TextField + { + id: textField + } + + Button + { + text: "Change Name" + onClicked: contact.name = textField.text + } + } +}