Qt for Python/Connecting QML Signals: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
 
No edit summary
Line 1: Line 1:
=Connecting <span class="caps">QML</span> signals in PySide=
[[Category:LanguageBindings::PySide]]<br />[[Category:Developing_with_Qt::Qt Quick]]<br />[toc align_right=&quot;yes&amp;quot; depth=&quot;3&amp;quot;]


This page describes a few alternative approaches for connecting signals between <span class="caps">QML</span> and PySide. Simple illustrative examples about the signal connectivity are also provided in the [http://qt.gitorious.org/pyside/pyside-examples/trees/master/examples/declarative/signals pyside-examples repository] ''[qt.gitorious.org]''. Browse the git tree directly or [http://qt.gitorious.org/pyside/pyside-examples/archive-tarball/master download a tarball of all examples] ''[qt.gitorious.org]'' and refer to the examples/declarative/signals directory.
= Connecting QML signals in PySide =


==Connecting signals from <span class="caps">QML</span> to Python==
This page describes a few alternative approaches for connecting signals between QML and PySide. Simple illustrative examples about the signal connectivity are also provided in the &quot;pyside-examples repository&amp;quot;:http://qt.gitorious.org/pyside/pyside-examples/trees/master/examples/declarative/signals. Browse the git tree directly or &quot;download a tarball of all examples&amp;quot;:http://qt.gitorious.org/pyside/pyside-examples/archive-tarball/master and refer to the examples/declarative/signals directory.


Connecting a signal from <span class="caps">QML</span> to Python is the most common use case. This allows for example connecting button clicks and other user interface events in <span class="caps">QML</span> to the backend logic written in Python.
== Connecting signals from QML to Python ==


There are multiple alternative methods for connecting <span class="caps">QML</span> signals to Python. The methods are not mutually exclusive; any of them can be used in a single program (and even for a single signal, if need be).
Connecting a signal from QML to Python is the most common use case. This allows for example connecting button clicks and other user interface events in QML to the backend logic written in Python.


===Explicitly calling a Python slot from <span class="caps">QML</span>===
There are multiple alternative methods for connecting QML signals to Python. The methods are not mutually exclusive; any of them can be used in a single program (and even for a single signal, if need be).


If the Python object is exposed to <span class="caps">QML</span> using <code>setContextProperty</code>, you can call any slot of the object explicitly from <span class="caps">QML</span>, as shown in [http://qt.gitorious.org/pyside/pyside-examples/trees/master/examples/declarative/signals/qmltopy1 qmltopy1] ''[qt.gitorious.org]''. First, you define a class in Python, inheriting from QObject:
=== Explicitly calling a Python slot from QML ===


Then, the Python object is instantiated and connected to the <span class="caps">QML</span> context:
If the Python object is exposed to QML using &lt;code&amp;gt;setContextProperty&amp;lt;/code&amp;gt;, you can call any slot of the object explicitly from QML, as shown in &quot;qmltopy1&amp;quot;:http://qt.gitorious.org/pyside/pyside-examples/trees/master/examples/declarative/signals/qmltopy1. First, you define a class in Python, inheriting from QObject:


After this, the object is accessible in <span class="caps">QML</span> and any slot can be called just like a function:
<code><br />class Console(QtCore.QObject):<br /> &amp;#64;QtCore.Slot(str)<br /> def outputStr(self, s):<br /> print s<br /></code>


===Returning a value from a slot===
Then, the Python object is instantiated and connected to the QML context:


It is possible for slots to return values to the <span class="caps">QML</span> caller (see example [http://qt.gitorious.org/pyside/pyside-examples/trees/master/examples/declarative/signals/qmltopy2 qmltopy2] ''[qt.gitorious.org]''). In this case, the Python slot needs to define an explicit return type:
<code><br />con = Console()<br />view = QtDeclarative.QDeclarativeView()<br />context = view.rootContext()<br />context.setContextProperty(&quot;con&amp;quot;, con)<br /></code>


Then the Python object is exposed to <span class="caps">QML</span>, after which it can be called just like a function:
After this, the object is accessible in QML and any slot can be called just like a function:


===Connecting signals from <span class="caps">QML</span> to Python using a top-level <span class="caps">QML</span> signal===
<code><br />MouseArea {<br /> onClicked: {<br /> con.outputStr(&quot;Hello, world!&quot;)<br /> }<br />}<br /></code>


If you prefer to handle the signal connection in Python, the simplest way to do it is to declare a top-level signal in <span class="caps">QML</span> and connect that to a Python slot as shown in [http://qt.gitorious.org/pyside/pyside-examples/trees/master/examples/declarative/signals/qmltopy3 example qmltopy3] ''[qt.gitorious.org]''.
=== Returning a value from a slot ===


First, in the top-level <span class="caps">QML</span> item, declare the signal:
It is possible for slots to return values to the QML caller (see example &quot;qmltopy2&amp;quot;:http://qt.gitorious.org/pyside/pyside-examples/trees/master/examples/declarative/signals/qmltopy2). In this case, the Python slot needs to define an explicit return type:


Then, in some other <span class="caps">QML</span> item, make some other signal handler emit this signal:
<code><br /> &amp;#64;QtCore.Slot(result=int)<br /> def val(self):<br /> self.r = self.r + 10<br /> return self.r<br /></code>


Finally, in Python, acquire the <span class="caps">QML</span> root object and connect the signal:
Then the Python object is exposed to QML, after which it can be called just like a function:


This approach has the benefit of hiding the Python class behaviour from <span class="caps">QML</span>. On the other hand, this approach requires the Python code to have some knowledge of the <span class="caps">QML</span> item contents.
<code><br /> onClicked: {<br /> helloText.rotation = rotatevalue.val()<br /> }<br /></code>


===Connecting a signal from a specific <span class="caps">QML</span> item to Python.===
=== Connecting signals from QML to Python using a top-level QML signal ===


It is also possible to acquire a specific <span class="caps">QML</span> item and connect a signal directly to it as illustrated in [http://qt.gitorious.org/pyside/pyside-examples/trees/master/examples/declarative/signals/qmltopy4 example qmltopy4] ''[qt.gitorious.org]''.
If you prefer to handle the signal connection in Python, the simplest way to do it is to declare a top-level signal in QML and connect that to a Python slot as shown in &quot;example qmltopy3&amp;quot;:http://qt.gitorious.org/pyside/pyside-examples/trees/master/examples/declarative/signals/qmltopy3.


In principle, this approach doesn’t require any extra consideration in <span class="caps">QML</span>. Unfortunately, in practice it may be difficult to find the proper <span class="caps">QML</span> items without assigning them object names:
First, in the top-level QML item, declare the signal:


Then, in Python, it is simple to find the desired item using <code>findChild</code> and connect a signal to it:
<code><br />Rectangle {<br /> id: page


Although initially tempting, this approach ties the <span class="caps">QML</span> and Python codebases pretty tightly to each other. Also, having to define the object names in <span class="caps">QML</span> makes the approach less than optimal.
signal textRotationChanged(double rot)


==Connecting signals from Python to <span class="caps">QML</span>==
[…]<br /></code>


It is also possible to connect signals from Python to <span class="caps">QML</span> when e.g. changes in the model data need to be reflected in the UI. [http://qt.gitorious.org/pyside/pyside-examples/trees/master/examples/declarative/signals/pytoqml1 Example pytoqml1] ''[qt.gitorious.org]'' illustrates how to do that.
Then, in some other QML item, make some other signal handler emit this signal:


First, a function is defined in <span class="caps">QML</span>:
<code><br /> onRotationChanged: textRotationChanged(rotation)<br /></code>


<span class="caps">QML</span> functions appear as slots in Python, so it’s a simple matter to connect a signal to them:
Finally, in Python, acquire the QML root object and connect the signal:


This allows for fairly clean and straightforward delivery of signals from Python to <span class="caps">QML</span>.
<code><br /> root = view.rootObject()<br /> root.textRotationChanged.connect(sayThis)<br /></code>


===Categories:===
This approach has the benefit of hiding the Python class behaviour from QML. On the other hand, this approach requires the Python code to have some knowledge of the QML item contents.


* [[:Category:Developing with Qt|Developing_with_Qt]]
=== Connecting a signal from a specific QML item to Python. ===
** [[:Category:Developing with Qt::Qt Quick|Qt_Quick]]
 
* [[:Category:LanguageBindings|LanguageBindings]]
It is also possible to acquire a specific QML item and connect a signal directly to it as illustrated in &quot;example qmltopy4&amp;quot;:http://qt.gitorious.org/pyside/pyside-examples/trees/master/examples/declarative/signals/qmltopy4.
** [[:Category:LanguageBindings::PySide|PySide]]
 
In principle, this approach doesn't require any extra consideration in QML. Unfortunately, in practice it may be difficult to find the proper QML items without assigning them object names:
 
<code><br /> MouseArea {<br /> id: buttonMouseArea<br /> objectName: &quot;buttonMouseArea&amp;quot;<br /> anchors.fill: parent<br /> }<br /></code>
 
Then, in Python, it is simple to find the desired item using &lt;code&amp;gt;findChild&amp;lt;/code&amp;gt; and connect a signal to it:
 
<code><br /> button = root.findChild(QtCore.QObject,&quot;buttonMouseArea&amp;quot;)<br /> button.clicked.connect(lambda: sayThis(&quot;clicked button (signal directly connected)&quot;))<br /></code>
 
Although initially tempting, this approach ties the QML and Python codebases pretty tightly to each other. Also, having to define the object names in QML makes the approach less than optimal.
 
== Connecting signals from Python to QML ==
 
It is also possible to connect signals from Python to QML when e.g. changes in the model data need to be reflected in the UI. &quot;Example pytoqml1&amp;quot;:http://qt.gitorious.org/pyside/pyside-examples/trees/master/examples/declarative/signals/pytoqml1 illustrates how to do that.
 
First, a function is defined in QML:
 
<code><br /> function updateRotater() {<br /> rotater.angle = rotater.angle + 45<br /> }<br /></code>
 
QML functions appear as slots in Python, so it's a simple matter to connect a signal to them:
 
<code><br /> timer.timeout.connect(root.updateRotater)<br /></code>
 
This allows for fairly clean and straightforward delivery of signals from Python to QML.

Revision as of 09:05, 24 February 2015



[toc align_right="yes&quot; depth="3&quot;]

Connecting QML signals in PySide

This page describes a few alternative approaches for connecting signals between QML and PySide. Simple illustrative examples about the signal connectivity are also provided in the "pyside-examples repository&quot;:http://qt.gitorious.org/pyside/pyside-examples/trees/master/examples/declarative/signals. Browse the git tree directly or "download a tarball of all examples&quot;:http://qt.gitorious.org/pyside/pyside-examples/archive-tarball/master and refer to the examples/declarative/signals directory.

Connecting signals from QML to Python

Connecting a signal from QML to Python is the most common use case. This allows for example connecting button clicks and other user interface events in QML to the backend logic written in Python.

There are multiple alternative methods for connecting QML signals to Python. The methods are not mutually exclusive; any of them can be used in a single program (and even for a single signal, if need be).

Explicitly calling a Python slot from QML

If the Python object is exposed to QML using <code&gt;setContextProperty&lt;/code&gt;, you can call any slot of the object explicitly from QML, as shown in "qmltopy1&quot;:http://qt.gitorious.org/pyside/pyside-examples/trees/master/examples/declarative/signals/qmltopy1. First, you define a class in Python, inheriting from QObject:

<br />class Console(QtCore.QObject):<br /> &amp;#64;QtCore.Slot(str)<br /> def outputStr(self, s):<br /> print s<br />

Then, the Python object is instantiated and connected to the QML context:

<br />con = Console()<br />view = QtDeclarative.QDeclarativeView()<br />context = view.rootContext()<br />context.setContextProperty(&quot;con&amp;quot;, con)<br />

After this, the object is accessible in QML and any slot can be called just like a function:

<br />MouseArea {<br /> onClicked: {<br /> con.outputStr(&quot;Hello, world!&quot;)<br /> }<br />}<br />

Returning a value from a slot

It is possible for slots to return values to the QML caller (see example "qmltopy2&quot;:http://qt.gitorious.org/pyside/pyside-examples/trees/master/examples/declarative/signals/qmltopy2). In this case, the Python slot needs to define an explicit return type:

<br /> &amp;#64;QtCore.Slot(result=int)<br /> def val(self):<br /> self.r = self.r + 10<br /> return self.r<br />

Then the Python object is exposed to QML, after which it can be called just like a function:

<br /> onClicked: {<br /> helloText.rotation = rotatevalue.val()<br /> }<br />

Connecting signals from QML to Python using a top-level QML signal

If you prefer to handle the signal connection in Python, the simplest way to do it is to declare a top-level signal in QML and connect that to a Python slot as shown in "example qmltopy3&quot;:http://qt.gitorious.org/pyside/pyside-examples/trees/master/examples/declarative/signals/qmltopy3.

First, in the top-level QML item, declare the signal:

<br />Rectangle {<br /> id: page

signal textRotationChanged(double rot)

[]<br />

Then, in some other QML item, make some other signal handler emit this signal:

<br /> onRotationChanged: textRotationChanged(rotation)<br />

Finally, in Python, acquire the QML root object and connect the signal:

<br /> root = view.rootObject()<br /> root.textRotationChanged.connect(sayThis)<br />

This approach has the benefit of hiding the Python class behaviour from QML. On the other hand, this approach requires the Python code to have some knowledge of the QML item contents.

Connecting a signal from a specific QML item to Python.

It is also possible to acquire a specific QML item and connect a signal directly to it as illustrated in "example qmltopy4&quot;:http://qt.gitorious.org/pyside/pyside-examples/trees/master/examples/declarative/signals/qmltopy4.

In principle, this approach doesn't require any extra consideration in QML. Unfortunately, in practice it may be difficult to find the proper QML items without assigning them object names:

<br /> MouseArea {<br /> id: buttonMouseArea<br /> objectName: &quot;buttonMouseArea&amp;quot;<br /> anchors.fill: parent<br /> }<br />

Then, in Python, it is simple to find the desired item using <code&gt;findChild&lt;/code&gt; and connect a signal to it:

<br /> button = root.findChild(QtCore.QObject,&quot;buttonMouseArea&amp;quot;)<br /> button.clicked.connect(lambda: sayThis(&quot;clicked button (signal directly connected)&quot;))<br />

Although initially tempting, this approach ties the QML and Python codebases pretty tightly to each other. Also, having to define the object names in QML makes the approach less than optimal.

Connecting signals from Python to QML

It is also possible to connect signals from Python to QML when e.g. changes in the model data need to be reflected in the UI. "Example pytoqml1&quot;:http://qt.gitorious.org/pyside/pyside-examples/trees/master/examples/declarative/signals/pytoqml1 illustrates how to do that.

First, a function is defined in QML:

<br /> function updateRotater() {<br /> rotater.angle = rotater.angle + 45<br /> }<br />

QML functions appear as slots in Python, so it's a simple matter to connect a signal to them:

<br /> timer.timeout.connect(root.updateRotater)<br />

This allows for fairly clean and straightforward delivery of signals from Python to QML.