可编辑的QTableView和Pandas不能正常工作

3
我正在尝试获取一个自包含的示例代码,用于使用pandas和QTableView同时获取可编辑单元格视图。
为此,我在跟进早期讨论: Pandas df in editable QTableView: remove check boxes 虽然那个讨论中的答案和建议的修改有助于摆脱复选框,但那里讨论的代码对我仍不起作用(python 2.7)。
当我使用下面的代码修改单元格时,单元格中显示的内容是:PtQt4.PtCore.QtVariant object at ...
我使用的软件包版本是:
Pandas: 0.20.2 Pyside 1.2.4 Qt version: 4.8.4 SIP version: 4.14.4 PyQt version: 4.10
import sys
from PyQt4 import QtCore, QtGui
import pandas as pd
Qt = QtCore.Qt

    class PandasModelEditable(QtCore.QAbstractTableModel):
    def __init__(self, data, parent=None):
        QtCore.QAbstractTableModel.__init__(self, parent)
        self._data = data

    def rowCount(self, parent=None):
        return len(self._data.values)

    def columnCount(self, parent=None):
        return self._data.columns.size

    def data(self, index, role=QtCore.Qt.DisplayRole):
        if index.isValid():
            if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole:
                return unicode(self._data.iloc[index.row(), index.column()])
        return None

    def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
        if role != QtCore.Qt.DisplayRole:
            return None
        if orientation == QtCore.Qt.Horizontal:
            try:
                return '%s' % unicode(self._data.columns.tolist()[section])
            except (IndexError,):
                return unicode()
        elif orientation == QtCore.Qt.Vertical:
            try:
                return '%s' % unicode(self._data.index.tolist()[section])
            except (IndexError,):
                return unicode()

    def flags(self, index):
        return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | \
               QtCore.Qt.ItemIsEditable

    def setData(self, index, value, role=QtCore.Qt.EditRole):
        if index.isValid():
            self._data.iloc[index.row(), index.column()] = value
            if self.data(index, QtCore.Qt.DisplayRole) == value:
                self.dataChanged.emit(index, index)
                return True
        return False


if __name__ == '__main__':
    application = QtGui.QApplication(sys.argv)
    view = QtGui.QTableView()
    df = pd.DataFrame([[1, 2, 3], [4, 5, 6]], columns=['a', 'b', 'c'], index=['x', 'y'])

    model = PandasModelEditable(df)
    view.setModel(model)

    view.show()
    sys.exit(application.exec_())
2个回答

2

产生这个问题的原因是将未转换的QVariant对象传递给底层数据库。最简单的解决方法是将其转换为Python对象,如下所示:

self._data.iloc[index.row(), index.column()] = value.toPyObject()

然而,这并没有真正解决代码中最根本的问题,即您正在使用如此旧版本的Python和PyQt。Qt不再官方支持Qt4,Python和Python2很快也将如此。严格来说,PyQt4已经是过时的遗留代码 - 因此,除非您有一个非常好的理由(例如向后兼容性),否则不应将其用于新项目。
如果可能的话,我强烈建议您尽快将代码移植到Python3/PyQt5,因为在中长期内这将为您节省大量麻烦。但是,如果出于某种原因您无法这样做,并且想继续使用Python2/PyQt4,则可以通过在程序开头添加以下内容来获得与PySide相同的行为:
import sip
sip.setapi('QString', 2)
sip.setapi('QVariant', 2)
from PyQt4 import QtCore, QtGui

完成这项操作后,PyQt将自动将所有的QStringQVariant对象转换为普通的Python数据类型,因此您永远不需要进行任何显式的转换(即可以删除代码中所有那些unicode()toPyObject()调用)。
另外,您还可以使用PyQt4与Python3一起使用,默认情况下具有与PySide相同的行为(因此不需要setapi)。

0

当我切换到PySide而不是PyQt4时,它似乎可以工作:

import sys
from PySide import QtCore, QtGui
import pandas as pd
Qt = QtCore.Qt

    class PandasModelEditable(QtCore.QAbstractTableModel):
    def __init__(self, data, parent=None):
        QtCore.QAbstractTableModel.__init__(self, parent)
        self._data = data

    def rowCount(self, parent=None):
        return len(self._data.values)

    def columnCount(self, parent=None):
        return self._data.columns.size

    def data(self, index, role=QtCore.Qt.DisplayRole):
        if index.isValid():
            if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole:
                return unicode(self._data.iloc[index.row(), index.column()])
        return None

    def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
        if role != QtCore.Qt.DisplayRole:
            return None
        if orientation == QtCore.Qt.Horizontal:
            try:
                return '%s' % unicode(self._data.columns.tolist()[section])
            except (IndexError,):
                return unicode()
        elif orientation == QtCore.Qt.Vertical:
            try:
                return '%s' % unicode(self._data.index.tolist()[section])
            except (IndexError,):
                return unicode()

    def flags(self, index):
        return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | \
               QtCore.Qt.ItemIsEditable

    def setData(self, index, value, role=QtCore.Qt.EditRole):
        if index.isValid():
            self._data.iloc[index.row(), index.column()] = value
            if self.data(index, QtCore.Qt.DisplayRole) == value:
                self.dataChanged.emit(index, index)
                return True
        return False


if __name__ == '__main__':
    application = QtGui.QApplication(sys.argv)
    view = QtGui.QTableView()
    df = pd.DataFrame([[1, 2, 3], [4, 5, 6]], columns=['a', 'b', 'c'], index=['x', 'y'])

    model = PandasModelEditable(df)
    view.setModel(model)

    view.show()
    sys.exit(application.exec_())

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接