mirror of https://github.com/status-im/nimqml.git
Updated the doc
This commit is contained in:
parent
3c11dbd0ac
commit
5c42890e5b
216
doc/nimqml.md
216
doc/nimqml.md
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue