在 QIODevice 子类中覆盖 readData 会返回不正确的结果

Posted

技术标签:

【中文标题】在 QIODevice 子类中覆盖 readData 会返回不正确的结果【英文标题】:Overriding readData in QIODevice subclass returns incorrect result 【发布时间】:2011-12-28 16:03:21 【问题描述】:

我正在尝试在 PySide 中对 QFile 进行子类化以实现自定义读取行为。但是,从下面的简化代码中可以看出,即使子类的 readData 实现只是调用了父类的 readData 函数,返回的数据也是不正确的。将其他 QIODevice 子类化(例如 QBuffer)也会导致返回值不正确。有没有人成功地将 QIODevice 子类化?

from PySide import QtCore

class FileChild1(QtCore.QFile):
    pass

class FileChild2(QtCore.QFile):
    def readData(self, maxlen):
        return super(FileChild2, self).readData(maxlen)


f1 = FileChild1('test.txt')
f1.open(QtCore.QIODevice.ReadWrite|QtCore.QIODevice.Truncate)
f1.write('Test text for testing')
f1.seek(0)
print 'FileChild1: ', repr(f1.read(50))

f2 = FileChild2('test2.txt')
f2.open(QtCore.QIODevice.ReadWrite|QtCore.QIODevice.Truncate)
f2.write('Test text for testing')
f2.seek(0)
print 'FileChild2: ', repr(f2.read(50))

>>> FileChild1:  PySide.QtCore.QByteArray('Test text for testing')
>>> FileChild2:  PySide.QtCore.QByteArray('─ Q ►│A☻ @  p¼a☻Test text for testing\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')

【问题讨论】:

在Qt原C++版本中,readData有如下签名qint64 QIODevice::readData ( char * data, qint64 maxSize ),其中数据被读入char数组并返回长度。在 PySide 和 PyQt 中,读取的数据直接以字符串形式返回。这种差异可能与它有关吗? 这在 PyQt4 中按预期工作(PyQt4:4.8.6,Qt:4.7.4)。也许是 PySide 中的错误? 【参考方案1】:

我用 PyQt 4.8 和 PyQt 4.9 用 Python 2.7.2 / Qt 4.8.0 测试了你的脚本,在这两种情况下它都会产生以下输出:

FileChild1:  'Test text for testing'
FileChild2:  'Test text for testing'

所以readData 根据PyQt4 docs 返回一个字节字符串。

将 PySide 1.0.9 与 Python 2.7.2 / Qt 4.8.0 一起使用,我得到以下输出:

FileChild1:  PySide.QtCore.QByteArray('Test text for testing')
FileChild2:  PySide.QtCore.QByteArray('')

不知道为什么 PyQt4 和 PySide 之间的返回类型存在差异,但 PySide 中显然存在某种错误。

有一个错误报告 here 看起来可能有点相关,但不是特别新(PySide 1.0.7)。

【讨论】:

存在这个bug实在是太可惜了,我宁愿用PySide,但是看起来我别无选择。【参考方案2】:

PySide 的 bug 来自 shiboken,即:qint64 在 QIODevice 中用作偏移类型,但 qint64 在 Python 2.x 中映射为“int”,而不是“long”。当 qint64 的值大于 qint32 时,读取该值会导致 Python 2.x 抛出 OverflowError。 当使用 qint64 作为 Slot/Signal/Property 或任何 Qt 元类型与 Python 通信 Qt C++ 代码时,会发生类似的溢出错误。

我也在寻找绕过这个问题的解决方案。

【讨论】:

【参考方案3】:

在 Qt5 和 PySide2 上也非常有效。我们正在调查。

【讨论】:

以上是关于在 QIODevice 子类中覆盖 readData 会返回不正确的结果的主要内容,如果未能解决你的问题,请参考以下文章

覆盖 QWebView 中的页面回复

跨工程传输数据

在子类中密封方法,因此孙子不能覆盖它

在基类中编写需要在子类中覆盖的方法实现?

UIWebView 在我的 UITableViewCell 子类中覆盖触摸事件

我想通过Python中的子类对象调用在子类中被覆盖的父类方法