简体   繁体   中英

How do I prevent PySide signals and slots from trying to convert binary string data to Unicode?

PySide signals and slots seem to be silently converting my binary strings to unicode. How can I avoid it? Alternatively, how can I pass along binary data via the signals-slots interface without PySide mutating it?

from PySide import QtCore

class Thingy(QtCore.QObject):
    data = QtCore.Signal(str)

@QtCore.Slot(str)
def printdata(x):
    print "type=%s, x=%s" % (type(x), x.__repr__())

thingy = Thingy()
thingy.data.connect(printdata)

for data in ('Hey', '\x55\xaa'):
    printdata(data)
    thingy.data.emit(data)

This prints out:

type=<type 'str'>, x='Hey'
type=<type 'unicode'>, x=u'Hey'
type=<type 'str'>, x='U\xaa'
type=<type 'unicode'>, x=u'U\xaa'

You can just replace the type specifier in the signal and the slot by object and PySide will not invoke any conversions.

from PySide import QtCore

class Thingy(QtCore.QObject):
    data = QtCore.Signal(object)

@QtCore.Slot(object)
def printdata(x):
    print "type=%s, x=%s" % (type(x), x.__repr__())

thingy = Thingy()
thingy.data.connect(printdata)

for data in ('Hey', '\x55\xaa'):
    printdata(data)
    thingy.data.emit(data)

gives

type=<type 'str'>, x='Hey'
type=<type 'str'>, x='Hey'
type=<type 'str'>, x='U\xaa'
type=<type 'str'>, x='U\xaa'

This allows you to send binary data.

I'm writing for python 2. In python 3 this situation is probably more sensible (but I don't know for sure).

Within Qt, the string class is QString . When pyside wants to pass a QString into python , it chooses the unicode type. This is a Good Thing, because QString supports unicode. There is no way to tell the Qt libs that the QString is actually supposed to be a byte array, so once your python str is converted to QString, you're going to get a unicode back. From this you see that the problem really happens when you pass your str into Qt and pyside converts the python str to QString.

Why does pyside convert python str to QString instead of eg. QByteArray ? In python 2 there isn't a separate type for byte arrays, so str does double duty as a byte array and as text. My guess is that QString is the default because str usually represents text.

If you had ASCII text, the simplest solution would be to just call str() at the beginning of your slot:

@QtCore.Slot(str)
def printdata(x):
    x = str(x)
    print "type=%s, x=%s" % (type(x), x.__repr__())

However, as you said in the question, you have binary data, so this won't work. One solution is to tell the signal to accept your own custom type:

class Thingy(QtCore.QObject):
    data = pyqtSignal(<your custom byte array type>)

You can then make your own byte array type which uses str under the hood (make sure it's a new style class).

Finally, you could just use QByteArray:

class Thingy(QtCore.QObject):
    data = pyqtSignal(QByteArray)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM