Python PyQt - 实现 QAbstractTableModel 以在 QTableView 中显示
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17697352/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
PyQt - Implement a QAbstractTableModel for display in QTableView
提问by drexiya
I would like to display a pandas data frame in a PyQt table. I have made some progress with this, but have not been able to correctly derive the Table Model class. Any help with this would be much appreciated.
我想在 PyQt 表中显示一个熊猫数据框。我在这方面取得了一些进展,但无法正确派生 Table Model 类。对此的任何帮助将不胜感激。
** Note full example code here**
** 注意这里的完整示例代码**
I am struggling to generate a valid QtCore.QAbstractTableModel derived class. Following on from a previous question about QItemDelegates I am trying to generate a table model from a Pandas DataFrame to insert real data. I have working example code here, but if I replace my TableModel with TableModel2 in the Widget class (ln 152) I cannot get the table to display.
我正在努力生成一个有效的 QtCore.QAbstractTableModel 派生类。继上一个关于 QItemDelegates 的问题之后,我试图从 Pandas DataFrame 生成表模型以插入真实数据。我在这里有工作示例代码,但是如果我用 Widget 类 (ln 152) 中的 TableModel2 替换我的 TableModel,我无法显示表格。
class TableModel2(QtCore.QAbstractTableModel):
def __init__(self, parent=None, *args):
super(TableModel2, self).__init__()
#QtCore.QAbstractTableModel.__init__(self, parent, *args)
self.datatable = None
self.headerdata = None
self.dataFrame = None
self.model = QtGui.QStandardItemModel(self)
def update(self, dataIn):
print 'Updating Model'
self.datatable = dataIn
print 'Datatable : {0}'.format(self.datatable)
headers = dataIn.columns.values
header_items = [
str(field)
for field in headers
]
self.headerdata = header_items
print 'Headers'
print self.headerdata
for i in range(len(dataIn.index.values)):
for j in range(len(dataIn.columns.values)):
#self.datatable.setItem(i,j,QtGui.QTableWidgetItem(str(df.iget_value(i, j))))
self.model.setItem(i,j,QtGui.QStandardItem(str(dataIn.iget_value(i, j))))
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.datatable.index)
def columnCount(self, parent=QtCore.QModelIndex()):
return len(self.datatable.columns.values)
def data(self, index, role=QtCore.Qt.DisplayRole):
if not index.isValid():
return QtCore.QVariant()
elif role != QtCore.Qt.DisplayRole:
return QtCore.QVariant()
#return QtCore.QVariant(self.model.data(index))
return QtCore.QVariant(self.model.data(index))
def headerData(self, col, orientation, role):
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
return QtCore.QVariant()
return QtCore.QVariant(self.headerdata[col])
def setData(self, index, value, role=QtCore.Qt.DisplayRole):
print "setData", index.row(), index.column(), value
def flags(self, index):
if (index.column() == 0):
return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled
else:
return QtCore.Qt.ItemIsEnabled
I am attempting to create the model and then add it to the view, like this:
我正在尝试创建模型,然后将其添加到视图中,如下所示:
class Widget(QtGui.QWidget):
"""
A simple test widget to contain and own the model and table.
"""
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
l=QtGui.QVBoxLayout(self)
cdf = self.get_data_frame()
self._tm=TableModel(self)
self._tm.update(cdf)
self._tv=TableView(self)
self._tv.setModel(self._tm)
for row in range(0, self._tm.rowCount()):
self._tv.openPersistentEditor(self._tm.index(row, 0))
l.addWidget(self._tv)
def get_data_frame(self):
df = pd.DataFrame({'Name':['a','b','c','d'],
'First':[2.3,5.4,3.1,7.7], 'Last':[23.4,11.2,65.3,88.8], 'Class':[1,1,2,1], 'Valid':[True, True, True, False]})
return df
Thanks for your attention!
感谢您的关注!
Note : Edit 2 I have incorporated the QStandardItemModel into TableModel2. Also deleted the dataFrameToQtTable function after @mata's comment. This is getting a bit closer but still not working.
注意:编辑 2 我已将 QStandardItemModel 合并到 TableModel2 中。在@mata 的评论之后也删除了 dataFrameToQtTable 函数。这越来越近了,但仍然无法正常工作。
采纳答案by drexiya
Ok I have figured this one out with the above suggestion and some help from the Rapid GUI book by Summerfield. There is no underlying model that exists in the QAbstractTableModel. Only three functions need be overridden, and the data may be stored in any user defined format, as long as it is returned in the data call.
好的,我已经根据上述建议和 Summerfield 的 Rapid GUI 一书中的一些帮助解决了这个问题。QAbstractTableModel 中不存在底层模型。只需要重写三个函数,数据可以以任何用户定义的格式存储,只要在数据调用中返回即可。
A very simple implementation could be:
一个非常简单的实现可能是:
class TableModel(QtCore.QAbstractTableModel):
def __init__(self, parent=None, *args):
super(TableModel, self).__init__()
self.datatable = None
def update(self, dataIn):
print 'Updating Model'
self.datatable = dataIn
print 'Datatable : {0}'.format(self.datatable)
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.datatable.index)
def columnCount(self, parent=QtCore.QModelIndex()):
return len(self.datatable.columns.values)
def data(self, index, role=QtCore.Qt.DisplayRole):
if role == QtCore.Qt.DisplayRole:
i = index.row()
j = index.column()
return '{0}'.format(self.datatable.iget_value(i, j))
else:
return QtCore.QVariant()
def flags(self, index):
return QtCore.Qt.ItemIsEnabled
This enables you to view any compatable data frame in a Qt view.
这使您能够在 Qt 视图中查看任何兼容的数据框。
I have updated the Gist over here
我已经在这里更新了要点
This should get you going quickly if you also need to do this.
如果您也需要这样做,这应该可以让您快速上手。
回答by mata
This is probably your problem:
这可能是你的问题:
def rowCount(self, parent=QtCore.QModelIndex()):
if type(self.datatable) == pd.DataFrame:
...
def columnCount(self, parent=QtCore.QModelIndex()):
if (self.datatable) == pd.DataFrame:
...
You set your datatable
to a QTableWidget
in dataFrameToQtTable
, so it can't be a pd.DataFrame
, your methods will always return 0.
您将您的设置datatable
为 a QTableWidget
in dataFrameToQtTable
,因此它不能是 a pd.DataFrame
,您的方法将始终返回 0。
Without the type check, you would have caught the problem immediately. Do you really want to silently ignore all cases where your type doesn't match (better let it raise an error if it doesn't follow the same interface you're expecting)? Typechecks are in most cases unnecessary.
如果没有类型检查,您会立即发现问题。您是否真的想默默地忽略您的类型不匹配的所有情况(如果它不遵循您期望的相同界面,最好让它引发错误)?类型检查在大多数情况下是不必要的。
回答by working4coins
Pandas 0.13 provides as an experimental feature:
Pandas 0.13 提供了一个实验性功能:
PySide support for the qtpandas DataFrameModel
and DataFrameWidget
PySide 支持 qtpandasDataFrameModel
和DataFrameWidget
see https://github.com/pydata/pandas/blob/master/doc/source/faq.rst
见https://github.com/pydata/pandas/blob/master/doc/source/faq.rst
you can add this feature using
您可以使用添加此功能
from pandas.sandbox.qtpandas import DataFrameModel, DataFrameWidget