Updated the doc

This commit is contained in:
Filippo Cucchetto 2019-10-01 23:56:29 +02:00
parent 3c11dbd0ac
commit 5c42890e5b
1 changed files with 92 additions and 124 deletions

View File

@ -2,8 +2,9 @@
Filippo Cucchetto <filippocucchetto@gmail.com>
Will Szumski <will@cowboycoders.org>
:Version: 0.4.5
:Date: 2015/09/15
:Version: 0.7.7
:Date: 2019/10/01
Introduction
-----------
@ -11,7 +12,7 @@ The NimQml module adds Qt Qml bindings to the Nim programming language
allowing you to create new modern UI by mixing the Qml declarative syntax
and the Nim imperative language.
The NimQml is made by two components:
You will need:
* The DOtherSide C++ shared library
* The NimQml Nim module
@ -19,7 +20,8 @@ This first component implements the glue code necessary for
communicating with the Qt C++ library, the latter module wraps
the libDOtherSide exported symbols in Nim
Building
Building the C++ DOtherSide bindings
--------
At the time of writing the DOtherSide C++ library must be compiled
and installed manually from source.
@ -35,34 +37,20 @@ than you can proceed with the common CMake build steps
cd build
cmake ..
make
make install
If everything goes correctly, you'll have built both
the DOtherSide C++ library and the Nim examples
Installation
Installation of NimQml module
----------
The installation is not mandatory, in fact you could try
the built Nim example in the following way
the built-in examples in the following way
::
cd path/to/build/dir
cd Nim/Examples/HelloWorld
cd path/to/repo/nimqml
cd examples/helloworld
export LD_LIBRARY_PATH=path/to/libDOtherSide.so
./HelloWorld
nim c -r main
The DOtherSide project is made of two components
1. The DOtherSide C++ lib
2. The NimQml module
You can procede with the installation of the C++ library
in the following way
::
cd to/build/dir
make install
or by manually copying the library in your system lib directory
::
sudo cp build/dir/path/DOtherSide/libDOtherSide.so /usr/lib
For the NimQml module you can use the ``nimble`` package manager
Alternatively you can use the ``nimble`` package manager
::
nimble install NimQml
@ -80,43 +68,42 @@ files. Usually the .nim files contains your app logic and data
layer. The qml files contain the presentation layer and expose
the data in your nim files.
``Examples/HelloWorld/main.nim``
``examples/helloworld/main.nim``
.. code-block:: nim
:file: ../Examples/HelloWorld/main.nim
:file: ../examples/helloworld/main.nim
``Examples/HelloWorld/main.qml``
``examples/helloworld/main.qml``
.. code-block:: qml
:file: ../Examples/HelloWorld/main.qml
:file: ../examples/helloworld/main.qml
The following example shows the basic steps of each NimQml app
1. Create the QApplication for initializing the Qt runtime
2. Create the QQmlApplicationEngine and load your main .qml file
3. Call the ``exec`` proc of the QApplication instance for starting
the Qt event loop
The example shows the mandatory steps of each NimQml app
1. Create the ``QApplication`` for initializing the Qt runtime
2. Create the `QQmlApplicationEngine` and load your main .qml file
3. Call the `exec` proc of the QApplication instance for starting the Qt event loop
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.
The previous example shown how to startup the Qt event loop
to create an application with a window.
It's time to explore how to pass data to Qml, but lets see the
It's time to explore how to pass data to Qml but lets see the
example code first:
``Examples/SimpleData/main.nim``
``examples/simpledata/main.nim``
.. code-block:: nim
:file: ../Examples/SimpleData/main.nim
:file: ../examples/simpledata/main.nim
``Examples/SimpleData/main.qml``
``examples/simpledata/main.qml``
.. code-block:: qml
:file: ../Examples/SimpleData/main.qml
:file: ../examples/simpledata/main.qml
The following example shows how to expose simple data types to Qml:
1. Create a QVariant and set its internal value.
2. Create a property in the Qml root context with a given name.
The example shows how to expose simple values to Qml:
1. Create a `QVariant` and set its value.
2. Set a property in the Qml root context with a given name.
Once a property is set through the ``setContextProperty`` proc, it's available
globally in all the Qml script loaded by the current engine (see the official Qt
@ -137,35 +124,32 @@ update the view when something changes in the data layer.
This is achieved by creating an object that derives from QObject.
A QObject is made of :
1. ``Slots``: slots are functions that could be called from the qml engine and/or connected to Qt signals
2. ``Signals``: signals allow the sending of events and be connected to slots
3. ``Properties``: properties allow the passing of data to
the Qml view and make it aware of changes in the data layer
1. ``slots``: functions that could be called from the qml engine and/or connected to Qt signals
2. ``signals``: functions for sending events and to which slots connect
3. ``properties``: properties allow 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 QObject `property` is made of three things:
* a read slot: a method that returns the current value of the property
* a write slot: a method that sets the value of the property
* a notify signal: emitted when the current value of the property is changed
We'll start by looking at the main.nim file
``Examples/SlotsAndProperties/main.nim``
``examples/slotsandproperties/main.nim``
.. code-block:: nim
:file: ../Examples/SlotsAndProperties/main.nim
:file: ../examples/slotsandproperties/main.nim
Here, nothing special happens 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
We can see:
1. The creation of a 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 follows:
``Examples/SlotsAndProperties/main.qml``
``examples/slotsandproperties/main.qml``
.. code-block:: qml
:file: ../Examples/SlotsAndProperties/main.qml
:file: ../examples/slotsandproperties/main.qml
The qml is made up of: a Label, a TextInput widget, and a button.
The label displays the contact name - this automatically updates when
@ -178,83 +162,67 @@ So where's the magic?
The magic is in the Contact.nim file
``Examples/SlotsAndProperties/Contact.nim``
``examples/slotsandproperties/contact.nim``
.. code-block:: nim
:file: ../Examples/SlotsAndProperties/Contact.nim
:file: ../examples/slotsandproperties/contact.nim
First we declare a QObject subclass and provide a simple
new method where we:
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
A Contact is a subtype derived from `QObject`
Looking at the ``getName`` and ``setName`` methods, you can see that slots, as defined in Nim,
are nothing more than standard methods. The method corresponding to the ``setName`` slot
demonstrates how to use the ``emit`` method to emit a signal.
The last thing to consider is the override of the ``onSlotCalled`` method.
This method is called by the NimQml library when an invocation occurs from
the Qml side for one of the slots belonging to the QObject.
The usual implementation for the onSlotCalled method consists of a
switch statement that forwards 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
-------------------------
The previous example shows how to create a simple QObject, however writing
all those ``register`` procs and writing the ``onSlotCalled`` method
becomes boring pretty soon.
Furthermore all this information can be automatically generated.
For this purpose you can import the NimQmlMacros module that provides
the QtObject macro.
Let's begin as usual with both the main.nim and main.qml files
``Examples/QtObjectMacro/main.nim``
Defining a `QObject` is done using the nim `QtObject` macro
.. code-block:: nim
:file: ../Examples/QtObjectMacro/main.nim
QtObject:
type Contact* = ref object of QObject
m_name: string
Inside the `QtObject` just define your subclass as your would normally do in Nim.
``Examples/QtObjectMacro/main.qml``
.. code-block:: qml
:file: ../Examples/QtObjectMacro/main.qml
Nothing is new in both the ``main.nim`` and ``main.qml`` with respect to
the previous example. What changed is the Contact object:
``Examples/QtObjectMacro/Contact.nim``
Since Nim doesn't support automatic invocation of base class constructors and destructors
you need to call manually the base class `setup` and `delete` functions.
.. code-block:: nim
:file: ../Examples/QtObjectMacro/Contact.nim
proc delete*(self: Contact) =
self.QObject.delete
In details:
1. Each QObject is defined inside the QtObject macro
2. Each slot is annotated with the ``{.slot.}`` pragma
3. Each signal is annotated with the ``{.signal.}`` pragma
4. Each property is created with the ``QtProperty`` macro
proc setup(self: Contact) =
self.QObject.setup
The ``QtProperty`` macro has the following syntax
Don't forget to call the `setup` function and `delete` in your exported constructor
procedure
.. code-block:: nim
QtProperty[typeOfProperty] nameOfProperty
proc newContact*(): Contact =
new(result, delete)
result.m_name = "InitialName"
result.setup
Example 5: ContactApp
The creation of a property is done in the following way:
.. code-block:: nim
QtProperty[string] name:
read = getName
write = setName
notify = nameChanged
A `QtProperty` is defined by a:
1. type, in this case `string`
2. name, in this case `name`
3. read slot, in this case `getName`
4. write slot, in this case `setName`
5. notify signal, in this case `nameChanged`
Looking at the ``getName`, `setName``, `nameChanged` procs, show that slots and signals
are nothing more than standard procedures annotated with `{.slot.}` and `{.signal.}`
Example 4: ContactApp
-------------------------
The last example tries to show you all the stuff presented
in the previous chapters and gives you an introduction to how
to expose lists to qml.
Qt models are a huge topic and explaining how they work is
Qt models are a huge topic and explaining in detail how they work is
out of scope. For further information please read the official
Qt documentation.
@ -262,17 +230,17 @@ The main file follows the basic logic of creating a qml
engine and exposing a QObject derived object "ApplicationLogic"
through a global "logic" property
``Examples/ContactApp/main.nim``
``examples/contactapp/main.nim``
.. code-block:: nim
:file: ../Examples/ContactApp/main.nim
:file: ../examples/contactapp/main.nim
The qml file shows a simple app with a central tableview
``Examples/ContactApp/main.qml``
``examples/contactapp/main.qml``
.. code-block:: qml
:file: ../Examples/ContactApp/main.qml
:file: ../examples/contactapp/main.qml
The important things to notice are:
1. The menubar load, save and exit items handlers call the logic load, save and exit slots
@ -281,10 +249,10 @@ The important things to notice are:
The ApplicationLogic object is as follows:
``Examples/ContactApp/ApplicationLogic.nim``
``examples/contactapp/applicationlogic.nim``
.. code-block:: nim
:file: ../Examples/ContactApp/ApplicationLogic.nim
:file: ../examples/contactapp/applicationlogic.nim
The ApplicationLogic object,
1. expose some slots for handling the qml menubar triggered signals
@ -292,10 +260,10 @@ The ApplicationLogic object,
The ContactList object is as follows:
``Examples/ContactApp/ContactList.nim``
``examples/contactapp/contactlist.nim``
.. code-block:: nim
:file: ../Examples/ContactApp/ContactList.nim
:file: ../examples/contactapp/contactlist.nim
The ContactList object:
1. overrides the ``rowCount`` method for returning the number of rows stored in the model