2017-06-25 61 views
2

我想获得一个自包含的示例代码片段,以获取可编辑的单元格视图时使用熊猫和QTableView。可编辑的QTableView和熊猫不能正常工作

为了这个,我跟进到一个较早的讨论: Pandas df in editable QTableView: remove check boxes

而在其他讨论帮助的答案,并提出修改摆脱复选框,代码讨论仍然有工作不适合我( python 2.7)。

当我用下面的代码修改的细胞,在细胞中示出的内容是:在PtQt4.PtCore.QtVariant对象...

我使用的软件包版本是:

熊猫:0.20.2
Pyside 1.2.4
的Qt版本:4.8.4
SIP版本:4.14.4 PyQt的版本: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_()) 

回答

1

眼前的问题是通过传递一个未转换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()调用)。或者,你也可以使用Python3与PyQt4,默认情况下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_())