Until the release of PyQt4 v4.9.4, when a signal was emitted to a Python slot
that was not decorated with
pyqtSlot()
, it would first
check that the underlying C++ receiver instance still existed. If it didn't
then the slot was ignored thereby reflecting the standard C++ behaviour.
In v4.9.4 (strictly speaking it was the release of SIP at the time) the check
was removed. It was done so that an object could connect its
destroyed()
signal to itself so that it could
monitor when its underlying C++ instance was destroyed. Unfortunately this
turned out to be an undocumented and incompatible change and a potential source
of obscure bugs for more common code.
In v4.11 the check was reintroduced - hence creating an incompatibility for any
code that relies on the v4.9.4 behaviour. As a workaround for this the
no_receiver_check
argument has been added to
connect()
which allows the check to be suppressed
on a per connection basis.
In previous versions a
QPyNullVariant
would always evaluate to
True
when converted to a bool.
在此版本
QPyNullVariant
will always evaluate to
False
when
converted to a bool. This makes it behave like
None
in these
circumstances.
In previous versions, when using v2 of the QVariant API (the default for Python
v3), there was no way to represent a null
QVariant
. Therefore when reading
values of certain types from an SQL model it was impossible to distinguish
between, for example, a null integer and an integer with the value zero.
In this version the
QPyNullVariant
class is used to represent a null
QVariant. Therefore the object read from an SQL model may now be a
QPyNullVariant
实例。
A null
QVariant
is only converted to a
QPyNullVariant
if the underlying
C++ type of the
QVariant
cannot be tested for null, i.e. it does not
implement an
isNull()
method. This ensures that existing code that uses
non-SQL models will continue to work unchanged.
In previous versions PyQt4 would always try and convert a Python list to a
QVariantList
. In this version PyQt4 will first try to convert it to a
QVariant
包含
QList<QObject
*>
, but only if
QList<QObject
*>
has been registered with Qt as a meta-type.
Normally it is only the
QtDeclarative
module that registers this
meta-type and so the behaviour of existing applications should be unchanged.
It is possible however that you might observe different conversion behaviour
after importing the
QtDeclarative
模块。
pyqtSignal()
with dict and list
¶
In previous versions a Qt signal defined using
pyqtSignal()
that had an argument specified as a dict then,
when emitting a value, PyQt4 would try and convert the value to a
QVariantMap
if possible. If it wasn't possible, normally because the dict
had non-string keys, then the value would be left as a dict object.
In this version PyQt4 will not attempt to convert the value to a
QVariantMap
and will always leave it as a dict object. If you want the
value to be converted to a
QVariantMap
then define the signal argument as
'QVariantMap'
.
The same applies to conversions between lists and
QVariantList
.
This version introduces a slight incompatibility in the conversion between
sub-classes of standard Python types and
QVariant
.
Take, for example, the following code:
from PyQt4.QtCore import QVariant
class MyFloat(float):
pass
myfloat = MyFloat(5.0)
variant = QVariant(myfloat)
With this version of PyQt4
myfloat
will be converted in such a way as to
preserve any additional attributes (including methods) and will not be
converted to a C++
double
. In other words, the following assertions are
true:
assert(variant.type() != QVariant.Double)
assert(variant.toPyObject() is myfloat)
Prior to this version
myfloat
would be converted to a C++
double
. In
other words, the following assertions would be true:
assert(variant.type() == QVariant.Double)
assert(variant.toPyObject() == myfloat)
assert(type(variant.toPyObject()) is float)
The same change also affects objects that implement the sequence protocol.
Prior to this version such an object would be converted to a
QVariantList
which would mean that it was converted back to a Python
list
rather than to
the original type.
This version introduces a slight incompatibility in the conversion between
Python sub-classes of certain Qt classes and
QVariant
. The Qt classes
affected are those that
QVariant
has explicit support for, e.g.
QSize
,
QBitmap
.
Take, for example, the following code:
from PyQt4.QtCore import QSize, QVariant
class MySize(QSize):
pass
mysize = MySize(5, 5)
variant = QVariant(mysize)
With this version of PyQt4
mysize
will be converted in such a way as to
preserve any additional attributes (including methods) and will not be
converted to a C++
QSize
instance. In other words, the following
assertions are true:
assert(variant.type() != QVariant.Size)
assert(variant.toPyObject() is mysize)
Prior to this version
mysize
would be converted to a C++
QSize
instance. In other words, the following assertions would be true:
assert(variant.type() == QVariant.Size)
assert(variant.toPyObject() == mysize)
assert(type(variant.toPyObject()) is QSize)
It is hoped that this change of behaviour will not have a significant impact. However if you need the old behaviour then simply create a copy of your sub-class instance using the base class constructor as shown below:
variant = QVariant(QSize(mysize))
A similar issue also affects the conversion of the Python
datetime
,
date
and
time
types to
QVariant
. These are no longer converted to
the corresponding
QDateTime
,
QDate
and
QTime
classes. The values
can be retrieved using
QVariant.toPyObject()
. Again, the old behaviour can
be achieved using an explicit conversion to the Qt class before converting to
QVariant
.
A further incompatible change is the handling of Python sub-classes of
QObject
. In previous versions
QVariant.userType()
would return an
internal type and an extra reference would be kept to the Python object. In
the current version
QVariant.userType()
will correctly return
QMetaType.QObjectStar
(或
QMetaType.QWidgetStar
) but an extra
reference to the Python object is not kept. To avoid a potential crash you
should ensure that you keep a separate reference to the Python object, either
explicitly or implicitly by giving it a parent.
pyrcc4
will now generate code for Python v3 when the new
-py3
command line option is used. The generated code
will also work with Python v2.6 and later.
默认情况下
pyrcc4
will generate code for all Python v2 versions but
you should use the new
-py2
command line option to
enforce this in case the default is changed in the future.