1
這個想法是通過PyQt5 MV編程習慣用法來顯示一個數據幀,並對提供的數據幀執行一些基本的排序和過濾操作。pyqt5 tableview在tablemodel上排序後沒有更新
顯示部分一切正常,但現在我被困在工具的排序部分。打印語句向我展示了它自己排序的數據框,它是未更新的視圖。所以,現在的代碼:
import sys
import operator
tmp = [('23-02-1978', '19:03:13', 'eh', None, 'even more some data'),
('23-02-1978', '19:01:45', 'ss', 'some data ', 'even more some data'),
('23-02-1978', '19:02:55', 'he', 'some data ', 'even more some data')]
tmp1 = [('23-02-1978', '19:02:33', 'eh', 'some data ', '666', 'even more some data'),
('23-02-1978', '19:03:22', 'ss', 'some data ', '777', 'even more some data'),
('23-02-1978', '19:01:45', 'he', 'some data ', '888', 'even more some data')]
from PyQt5.QtWidgets import (QMainWindow, QApplication, QWidget, QAction,
QGroupBox, QCheckBox, QTableView, QTableWidgetItem,
QTabWidget, QGridLayout,QLineEdit, QFormLayout,
QVBoxLayout, QHBoxLayout, QLabel, QDialog, QHeaderView)
from PyQt5.QtGui import QIcon, QFont
from PyQt5.QtCore import Qt, pyqtSlot, pyqtSignal, QAbstractTableModel, QVariant, QModelIndex, QSortFilterProxyModel
from pandas import DataFrame
class DataFrameModel(QAbstractTableModel):
def __init__(self):
""" datain: a list of lists
headerdata: a list of strings
"""
super(DataFrameModel, self).__init__()
self._df = DataFrame()
def setDataFrame(self, df):
self._df = df;
def signalUpdate(self):
''' tell viewers to update their data (this is full update, not
efficient)'''
self.layoutChanged.emit()
#------------- table display functions -----------------
def headerData(self, section, orientation, role=Qt.DisplayRole):
if role != Qt.DisplayRole:
return QVariant()
if orientation == Qt.Horizontal:
try:
return self._df.columns.tolist()[section]
except (IndexError,):
return QVariant()
elif orientation == Qt.Vertical:
try:
# return self.df.index.tolist()
return self._df.index.tolist()[section]
except (IndexError,):
return QVariant()
def data(self, index, role=Qt.DisplayRole):
if role != Qt.DisplayRole:
return QVariant()
if not index.isValid():
return QVariant()
return QVariant(str(self._df.ix[index.row(), index.column()]))
def flags(self, index):
flags = super(DataFrameModel, self).flags(index)
return flags
def setData(self, index, value, role):
row = self._df.index[index.row()]
col = self._df.columns[index.column()]
if hasattr(value, 'toPyObject'):
# PyQt4 gets a QVariant
value = value.toPyObject()
else:
# PySide gets an unicode
dtype = self._df[col].dtype
if dtype != object:
value = None if value == '' else dtype.type(value)
self._df.set_value(row, col, value)
return True
def rowCount(self, parent=QModelIndex()):
return len(self._df.index)
def columnCount(self, parent=QModelIndex()):
return len(self._df.columns)
def sort(self, column, order=Qt.AscendingOrder):
"""Sort table by given column number.
"""
print('sort clicked col {} order {}'.format(column, order))
self.layoutAboutToBeChanged.emit()
print(self._df.columns[column])
self._df.sort_values('time', ascending=order == Qt.AscendingOrder, inplace=True)
print(self._df)
self.layoutChanged.emit()
class DataFrameWidget(QWidget):
''' a simple widget for using DataFrames in a gui '''
def __init__(self, dataFrame, parent=None):
super(DataFrameWidget, self).__init__(parent)
self.dataModel = DataFrameModel()
# Set DataFrame
self.dataTable = QTableView()
# self.proxy = QSortFilterProxyModel()
# self.proxy.setSourceModel(self.dataModel)
self.dataTable.setModel(self.dataModel)
self.dataTable.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
self.setDataFrame(dataFrame)
self.dataTable.setSortingEnabled(True)
self.dataTable.sortByColumn(0,0)
layout = QVBoxLayout()
layout.addWidget(self.dataTable)
self.setLayout(layout)
def setDataFrame(self, dataFrame):
self.dataModel.setDataFrame(dataFrame)
self.dataModel.signalUpdate()
def testDf():
''' creates test dataframe '''
# data = {'int': [1, 2, 3], 'float': [1.5, 2.5, 3.5],
# 'string': ['a', 'b', 'c'], 'nan': [np.nan, np.nan, np.nan]}
# data = [(1, 1.5, 'a', np.nan),
# (2, 2.5, 'b', np.nan),
# (3, 3.5, 'c', np.nan)]
return DataFrame(tmp, columns=['date', 'time', 'string', 'nan', 'bla'])
class Form(QDialog):
def __init__(self, parent=None):
super(Form, self).__init__(parent)
df = testDf() # make up some data
widget = DataFrameWidget(df)
layout = QVBoxLayout()
layout.addWidget(widget)
self.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
form = Form()
form.show()
exit(app.exec_())
使用SortFilterProxy工作了這個例子,但在更大的dataframes很慢。
上面的代碼expample確實工作,讀取排序,爲非數據框數據。用元組列表創建模型/視圖很好。
我發現的建議主要有兩個方向:記住要表示視圖或使用sortfilterproxy。我記得並嘗試過,但至今沒有成功。似乎與使用數據幀有關。歡迎提供所有建議。提前致謝。
重置索引,該死的看着錯誤的方向。感謝您的快速回復,我一回家就會改變這一點。 –
如果我的答案可以幫助您將其標記爲正確。 :P – eyllanesc