Differences Between PySide and PyQt: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
 
No edit summary
Line 1: Line 1:
'''English''' [[Differences-Between-PySide-and-PyQt-SimplifiedChinese|简体中文]]<br />
[[Category:LanguageBindings::PySide]]<br />'''English''' [[Differences Between PySide and PyQt SimplifiedChinese|简体中文]]<br />[toc align_right=&quot;yes&amp;quot; depth=&quot;3&amp;quot;]


=Differences Between PySide and PyQt=
= Differences Between PySide and PyQt =


==<span class="caps">API</span> differences==
== API differences ==


===Different import name (PySide instead of PyQt4)===
=== Different import name (PySide instead of PyQt4) ===


PySide uses a different library name than PyQt. Instead of typing:
PySide uses a different library name than PyQt. Instead of typing:
<code><br />from PyQt4.QtCore import *<br /></code>


or
or
<code><br />import PyQt4.QtCore<br /></code>


you have to do the following:
you have to do the following:


or<br /> .
<code><br />from PySide.QtCore import *<br /></code><br />or<br /><code><br />import PySide.QtCore<br /></code><br />.


===PySide only supports PyQt’s “<span class="caps">API</span> 2” (<span class="caps">PSEP</span> 101)===
=== PySide only supports PyQt's &quot;API 2&amp;quot; (PSEP 101) ===


PyQt provides [http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/pyqt4ref.html#selecting-incompatible-apis two different <span class="caps">API</span>s] ''[riverbankcomputing.co.uk]'', the first of which provides <code>QStrings</code>, <code>QVariants</code>, etc as is in Python. The new <span class="caps">API</span> 2 provides automatic conversion between the Qt classes and respective native Python datatypes and is much more Pythonic in nature. PyQt on Python 2.x defaults to <span class="caps">API</span> 1, while PyQt on Python 3 defaults to <span class="caps">API</span> 2.
PyQt provides &quot;two different APIs&amp;quot;:http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/pyqt4ref.html#selecting-incompatible-apis, the first of which provides &lt;code&amp;gt;QStrings&amp;lt;/code&amp;gt;, &lt;code&amp;gt;QVariants&amp;lt;/code&amp;gt;, etc as is in Python. The new API 2 provides automatic conversion between the Qt classes and respective native Python datatypes and is much more Pythonic in nature. PyQt on Python 2.x defaults to API 1, while PyQt on Python 3 defaults to API 2.


PySide only supports PyQt’s <span class="caps">API</span> 2 (see [http://www.pyside.org/docs/pseps/psep-0101.html <span class="caps">PSEP</span> 101] ''[pyside.org]'') for details. Therefore Qt classes such as <code>QStrings</code>, <code>QStringLists</code>, and <code>QVariants</code> are not available on PySide. Instead, you should simply use native Python datatypes.
PySide only supports PyQt's API 2 (see &quot;PSEP 101&amp;quot;:http://www.pyside.org/docs/pseps/psep-0101.html) for details. Therefore Qt classes such as &lt;code&amp;gt;QStrings&amp;lt;/code&amp;gt;, &lt;code&amp;gt;QStringLists&amp;lt;/code&amp;gt;, and &lt;code&amp;gt;QVariants&amp;lt;/code&amp;gt; are not available on PySide. Instead, you should simply use native Python datatypes.


If you’re porting code from PyQt, you might want to first modify the PyQt code to use <span class="caps">API</span> 2 (using a <code>sip.setapi(class,ver)</code> call before importing PyQt4), and only after getting that change working, change the imports to use PySide instead.
If you're porting code from PyQt, you might want to first modify the PyQt code to use API 2 (using a &lt;code&amp;gt;sip.setapi(class,ver)&lt;/code&amp;gt; call before importing PyQt4), and only after getting that change working, change the imports to use PySide instead.


'''NB:''' Due to the <span class="caps">API</span> change, <code>QFileDialog.getOpenFileName</code> returns a tuple in PySide, which often is an issue when porting code from PyQt. See e.g. [http://bugs.openbossa.org/show_bug.cgi?id=343 bug 343] ''[bugs.openbossa.org]''.
'''NB:''' Due to the API change, &lt;code&amp;gt;QFileDialog.getOpenFileName&amp;lt;/code&amp;gt; returns a tuple in PySide, which often is an issue when porting code from PyQt. See e.g. &quot;bug 343&amp;quot;:http://bugs.openbossa.org/show_bug.cgi?id=343.


===New-style signals and slots use slightly different syntax (<span class="caps">PSEP</span> 100)===
=== New-style signals and slots use slightly different syntax (PSEP 100) ===


PyQt unfortunately uses an implementation-specific naming scheme for its new-style signal and slot classes:
PyQt unfortunately uses an implementation-specific naming scheme for its new-style signal and slot classes:


As described in [http://www.pyside.org/docs/pseps/psep-0100.html <span class="caps">PSEP</span> 100] ''[pyside.org]'', use <code>QtCore.Signal()</code> and <code>QtCore.Slot()</code> instead.
<code><br /># Define a new signal called 'trigger' that has no arguments.<br />trigger = QtCore.pyqtSignal()<br /></code>
 
As described in &quot;PSEP 100&amp;quot;:http://www.pyside.org/docs/pseps/psep-0100.html, use &lt;code&amp;gt;QtCore.Signal()&lt;/code&amp;gt; and &lt;code&amp;gt;QtCore.Slot()&lt;/code&amp;gt; instead.


If you want to modify your PyQt code to use the PySide naming scheme, that can be done using a simple definition:
If you want to modify your PyQt code to use the PySide naming scheme, that can be done using a simple definition:


.
<code><br />QtCore.Signal = QtCore.pyqtSignal<br />QtCore.Slot = QtCore.pyqtSlot<br /></code><br />.


===Declaring Qt Properties is done using a slightly different syntax (<span class="caps">PSEP</span> 103)===
=== Declaring Qt Properties is done using a slightly different syntax (PSEP 103) ===


As with the signal/slot syntax change above, declaring Qt Properties is done using <code>QtCore</code>. Property instead of <code>QtCore.pyqtProperty</code> (see [http://www.pyside.org/docs/pseps/psep-0103.html <span class="caps">PSEP</span> 103] ''[pyside.org]'').
As with the signal/slot syntax change above, declaring Qt Properties is done using &lt;code&amp;gt;QtCore&amp;lt;/code&amp;gt;. Property instead of &lt;code&amp;gt;QtCore.pyqtProperty&amp;lt;/code&amp;gt; (see &quot;PSEP 103&amp;quot;:http://www.pyside.org/docs/pseps/psep-0103.html).


===Tool names different===
=== Tool names different ===


PySide uses different names for the tools scripts:
PySide uses different names for the tools scripts:


* pyuic4 -&gt; pyside-uic
* pyuic4 <s>&gt; pyside-uic<br />* pyrcc4</s>&gt; pyside-rcc
* pyrcc4 -&gt; pyside-rcc
* pylupdate4 -&gt; pyside-lupdate
* pylupdate4 -&gt; pyside-lupdate


===Property Names===
=== Property Names ===


PySide uses <code>connect</code> and <code>event</code> in the <code>QObject</code>. Do not use these for anything in your code, and when moving code from PyQt look for any that exist.
PySide uses &lt;code&amp;gt;connect&amp;lt;/code&amp;gt; and &lt;code&amp;gt;event&amp;lt;/code&amp;gt; in the &lt;code&amp;gt;QObject&amp;lt;/code&amp;gt;. Do not use these for anything in your code, and when moving code from PyQt look for any that exist.


===QThreads===
=== QThreads ===


In PySide you should <code>.wait()</code> on a thread after calling <code>.stop()</code> if you are quitting the application. Otherwise you may receive
In PySide you should &lt;code&amp;gt;.wait()&lt;/code&amp;gt; on a thread after calling &lt;code&amp;gt;.stop()&lt;/code&amp;gt; if you are quitting the application. Otherwise you may receive


<code>QThread: Destroyed while thread is still running<br /> Segmentation fault</code>
&lt;code&amp;gt;QThread: Destroyed while thread is still running<br />Segmentation fault&amp;lt;/code&amp;gt;


==Differences in the functionality of the bindings==
== Differences in the functionality of the bindings ==


===Bindings for functions deprecated before Qt 4.5 are not generated===
=== Bindings for functions deprecated before Qt 4.5 are not generated ===


Bindings for functions deprecated before Qt 4.5 are not generated in PySide.
Bindings for functions deprecated before Qt 4.5 are not generated in PySide.


If a function is not present in PySide, check the [http://doc.qt.nokia.com/ Qt Online Reference Documentation] ''[doc.qt.nokia.com]'' and see whether the function has been deprecated and what to use instead.
If a function is not present in PySide, check the &quot;Qt Online Reference Documentation&amp;quot;:http://doc.qt.nokia.com/ and see whether the function has been deprecated and what to use instead.


Example bug: [http://bugs.openbossa.org/show_bug.cgi?id=359 bug 359] ''[bugs.openbossa.org]''
Example bug: &quot;bug 359&amp;quot;:http://bugs.openbossa.org/show_bug.cgi?id=359


For example, this affects functions such as <code>QColor.dark()</code> and <code>QColor.light()</code>, instead of which <code>QColor.darker()</code> and <code>QColor.lighter()</code> need to be used.
For example, this affects functions such as &lt;code&amp;gt;QColor.dark()&lt;/code&amp;gt; and &lt;code&amp;gt;QColor.light()&lt;/code&amp;gt;, instead of which &lt;code&amp;gt;QColor.darker()&lt;/code&amp;gt; and &lt;code&amp;gt;QColor.lighter()&lt;/code&amp;gt; need to be used.


===sender() method returns None when used within a partial or a lambda===
=== sender() method returns None when used within a partial or a lambda ===


If a lambda is used as a slot, <code>sender()</code> cannot be used to acquire the object that emitted the signal. This works in PyQt, but their implementation behaves incorrectly in certain situations. See [http://bugs.openbossa.org/show_bug.cgi?id=344 bug 344] ''[bugs.openbossa.org]'' for details.
If a lambda is used as a slot, &lt;code&amp;gt;sender()&lt;/code&amp;gt; cannot be used to acquire the object that emitted the signal. This works in PyQt, but their implementation behaves incorrectly in certain situations. See &quot;bug 344&amp;quot;:http://bugs.openbossa.org/show_bug.cgi?id=344 for details.


===When inheriting classes, parent class constructors need to be always called===
=== When inheriting classes, parent class constructors need to be always called ===


PyQt in some cases allows code such as:
PyQt in some cases allows code such as:
<code><br />class Window(QtGui.QWidget):<br /> def ''init''(self, parent=None):<br /> super(QtGui.QWidget, self).''init''(parent)<br /> […]<br /></code>


in which the direct parent class constructor is not called. PySide expects you to do the right thing:
in which the direct parent class constructor is not called. PySide expects you to do the right thing:


===Old style signals need use of parentheses===
<code><br />class Window(QtGui.QWidget):<br /> def ''init''(self, parent=None):<br /> super(Window, self).''init''(parent)<br /> […]<br /></code>
 
=== Old style signals need use of parentheses ===


PyQt allows the use of short-circuit signals without parentheses such as:
PyQt allows the use of short-circuit signals without parentheses such as:
<code><br />self.emit(SIGNAL (&amp;#39;text_changed_cb&amp;#39;), text)<br /></code>


Since this is an old and deprecated feature, and the effort to fix this is not worth it, we decided to not implement it. In PySide code you need to use something like:
Since this is an old and deprecated feature, and the effort to fix this is not worth it, we decided to not implement it. In PySide code you need to use something like:


You can check the complete discussion on [http://bugs.pyside.org/show_bug.cgi?id=314 bug #314] ''[bugs.pyside.org]''
<code><br />self.emit(SIGNAL (&amp;#39;text_changed_cb(QString)'), text)<br /></code>


===Only signals without arguments can be auto connected on constructor.===
You can check the complete discussion on &quot;bug #314&amp;quot;:http://bugs.pyside.org/show_bug.cgi?id=314
 
=== Only signals without arguments can be auto connected on constructor. ===


If you use:
If you use:
<code><br />action = QtGui.QAction(None, triggered=handler)<br /></code>


The triggered() signal will be connected to the slot handler instead of the triggered(bool) signal.
The triggered() signal will be connected to the slot handler instead of the triggered(bool) signal.


=Supporting Both <span class="caps">API</span>s=
= Supporting Both APIs =
 
[https://github.com/epage/PythonUtils/blob/master/util/qt_compat.py qt_compat.py] ''[github.com]'' is an example of centralizing the knowledge of PySide and PyQt without using monkey-patching. It serves both to point out what differences exist as well as keeping your code binding-agnostic. This is important for when needing to support both bindings, usually when transitioning from one to the other and needing to continue to support older distributions that do not yet come with PySide.
 
=Converting PyQt4 code to PySide=


[https://github.com/prusnak/pysider pysider] ''[github.com]'' is a simple utility that converts your PyQt4 code to PySide.
&quot;qt_compat.py&amp;quot;:https://github.com/epage/PythonUtils/blob/master/util/qt_compat.py is an example of centralizing the knowledge of PySide and PyQt without using monkey-patching. It serves both to point out what differences exist as well as keeping your code binding-agnostic. This is important for when needing to support both bindings, usually when transitioning from one to the other and needing to continue to support older distributions that do not yet come with PySide.


===Categories:===
&quot;python_qt_binding&amp;quot;:https://github.com/ros-visualization/python_qt_binding is a Python package from the &quot;ROS&amp;quot;:http://www.ros.org middleware which gives a more extensive example of how to keep your code agnostic of the actual Python-Qt binding used. It offers a very transparent abstraction, allowing you to write standard import lines like <code>from python_qt_binding.QtCore import QObject<code> Furthermore it provides a substitute '''loadUi''' function for simple loading of ui files that work the same with both bindings. For usage examples see &quot;rqt_gui&amp;quot;:https://github.com/ros-visualization/rqt


* [[:Category:LanguageBindings|LanguageBindings]]
= Converting PyQt4 code to PySide =
** [[:Category:LanguageBindings::PySide|PySide]]

Revision as of 14:11, 23 February 2015


English 简体中文
[toc align_right="yes&quot; depth="3&quot;]

Differences Between PySide and PyQt

API differences

Different import name (PySide instead of PyQt4)

PySide uses a different library name than PyQt. Instead of typing:

<br />from PyQt4.QtCore import *<br />

or

<br />import PyQt4.QtCore<br />

you have to do the following:

<br />from PySide.QtCore import *<br />


or

<br />import PySide.QtCore<br />


.

PySide only supports PyQt's "API 2&quot; (PSEP 101)

PyQt provides "two different APIs&quot;:http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/pyqt4ref.html#selecting-incompatible-apis, the first of which provides <code&gt;QStrings&lt;/code&gt;, <code&gt;QVariants&lt;/code&gt;, etc as is in Python. The new API 2 provides automatic conversion between the Qt classes and respective native Python datatypes and is much more Pythonic in nature. PyQt on Python 2.x defaults to API 1, while PyQt on Python 3 defaults to API 2.

PySide only supports PyQt's API 2 (see "PSEP 101&quot;:http://www.pyside.org/docs/pseps/psep-0101.html) for details. Therefore Qt classes such as <code&gt;QStrings&lt;/code&gt;, <code&gt;QStringLists&lt;/code&gt;, and <code&gt;QVariants&lt;/code&gt; are not available on PySide. Instead, you should simply use native Python datatypes.

If you're porting code from PyQt, you might want to first modify the PyQt code to use API 2 (using a <code&gt;sip.setapi(class,ver)</code&gt; call before importing PyQt4), and only after getting that change working, change the imports to use PySide instead.

NB: Due to the API change, <code&gt;QFileDialog.getOpenFileName&lt;/code&gt; returns a tuple in PySide, which often is an issue when porting code from PyQt. See e.g. "bug 343&quot;:http://bugs.openbossa.org/show_bug.cgi?id=343.

New-style signals and slots use slightly different syntax (PSEP 100)

PyQt unfortunately uses an implementation-specific naming scheme for its new-style signal and slot classes:

<br /># Define a new signal called 'trigger' that has no arguments.<br />trigger = QtCore.pyqtSignal()<br />

As described in "PSEP 100&quot;:http://www.pyside.org/docs/pseps/psep-0100.html, use <code&gt;QtCore.Signal()</code&gt; and <code&gt;QtCore.Slot()</code&gt; instead.

If you want to modify your PyQt code to use the PySide naming scheme, that can be done using a simple definition:

<br />QtCore.Signal = QtCore.pyqtSignal<br />QtCore.Slot = QtCore.pyqtSlot<br />


.

Declaring Qt Properties is done using a slightly different syntax (PSEP 103)

As with the signal/slot syntax change above, declaring Qt Properties is done using <code&gt;QtCore&lt;/code&gt;. Property instead of <code&gt;QtCore.pyqtProperty&lt;/code&gt; (see "PSEP 103&quot;:http://www.pyside.org/docs/pseps/psep-0103.html).

Tool names different

PySide uses different names for the tools scripts:

  • pyuic4 > pyside-uic
    * pyrcc4
    > pyside-rcc
  • pylupdate4 -> pyside-lupdate

Property Names

PySide uses <code&gt;connect&lt;/code&gt; and <code&gt;event&lt;/code&gt; in the <code&gt;QObject&lt;/code&gt;. Do not use these for anything in your code, and when moving code from PyQt look for any that exist.

QThreads

In PySide you should <code&gt;.wait()</code&gt; on a thread after calling <code&gt;.stop()</code&gt; if you are quitting the application. Otherwise you may receive

<code&gt;QThread: Destroyed while thread is still running
Segmentation fault&lt;/code&gt;

Differences in the functionality of the bindings

Bindings for functions deprecated before Qt 4.5 are not generated

Bindings for functions deprecated before Qt 4.5 are not generated in PySide.

If a function is not present in PySide, check the "Qt Online Reference Documentation&quot;:http://doc.qt.nokia.com/ and see whether the function has been deprecated and what to use instead.

Example bug: "bug 359&quot;:http://bugs.openbossa.org/show_bug.cgi?id=359

For example, this affects functions such as <code&gt;QColor.dark()</code&gt; and <code&gt;QColor.light()</code&gt;, instead of which <code&gt;QColor.darker()</code&gt; and <code&gt;QColor.lighter()</code&gt; need to be used.

sender() method returns None when used within a partial or a lambda

If a lambda is used as a slot, <code&gt;sender()</code&gt; cannot be used to acquire the object that emitted the signal. This works in PyQt, but their implementation behaves incorrectly in certain situations. See "bug 344&quot;:http://bugs.openbossa.org/show_bug.cgi?id=344 for details.

When inheriting classes, parent class constructors need to be always called

PyQt in some cases allows code such as:

<br />class Window(QtGui.QWidget):<br /> def ''init''(self, parent=None):<br /> super(QtGui.QWidget, self).''init''(parent)<br /> []<br />

in which the direct parent class constructor is not called. PySide expects you to do the right thing:

<br />class Window(QtGui.QWidget):<br /> def ''init''(self, parent=None):<br /> super(Window, self).''init''(parent)<br /> []<br />

Old style signals need use of parentheses

PyQt allows the use of short-circuit signals without parentheses such as:

<br />self.emit(SIGNAL (&amp;#39;text_changed_cb&amp;#39;), text)<br />

Since this is an old and deprecated feature, and the effort to fix this is not worth it, we decided to not implement it. In PySide code you need to use something like:

<br />self.emit(SIGNAL (&amp;#39;text_changed_cb(QString)'), text)<br />

You can check the complete discussion on "bug #314&quot;:http://bugs.pyside.org/show_bug.cgi?id=314

Only signals without arguments can be auto connected on constructor.

If you use:

<br />action = QtGui.QAction(None, triggered=handler)<br />

The triggered() signal will be connected to the slot handler instead of the triggered(bool) signal.

Supporting Both APIs

"qt_compat.py&quot;:https://github.com/epage/PythonUtils/blob/master/util/qt_compat.py is an example of centralizing the knowledge of PySide and PyQt without using monkey-patching. It serves both to point out what differences exist as well as keeping your code binding-agnostic. This is important for when needing to support both bindings, usually when transitioning from one to the other and needing to continue to support older distributions that do not yet come with PySide.

"python_qt_binding&quot;:https://github.com/ros-visualization/python_qt_binding is a Python package from the "ROS&quot;:http://www.ros.org middleware which gives a more extensive example of how to keep your code agnostic of the actual Python-Qt binding used. It offers a very transparent abstraction, allowing you to write standard import lines like from python_qt_binding.QtCore import QObject Furthermore it provides a substitute loadUi function for simple loading of ui files that work the same with both bindings. For usage examples see "rqt_gui&quot;:https://github.com/ros-visualization/rqt

Converting PyQt4 code to PySide