以下是我正在使用的示例代码:
from PyQt4 import QtCore, QtGui
import pandas as pd
import re
import sys
import datetime as dt
class MainWindow(QtGui.QWidget):
def __init__(self):
self.app = QtGui.QApplication(sys.argv)
super(MainWindow, self).__init__()
layout = QtGui.QVBoxLayout()
top = QtGui.QHBoxLayout()
self.setLayout(layout)
self.inputBox = QtGui.QLineEdit()
self.tableView = QtGui.QTableView()
self.startDate = QtGui.QDateEdit()
self.stopDate = QtGui.QDateEdit()
self.startDate.setCalendarPopup(True)
self.stopDate.setCalendarPopup(True)
self.startDate.setDateRange(QtCore.QDate(2016, 1, 1), QtCore.QDate(2016, 1, 31))
self.stopDate.setDateRange(QtCore.QDate(2016, 1, 1), QtCore.QDate(2016, 1, 31))
self.startDate.setDate(QtCore.QDate(2016, 1, 1))
self.stopDate.setDate(QtCore.QDate(2016, 1, 15))
top.addWidget(self.inputBox)
top.addWidget(self.startDate)
top.addWidget(self.stopDate)
layout.addLayout(top)
layout.addWidget(self.tableView)
self.inputBox.textChanged.connect(self._textChanged)
self.startDate.dateChanged.connect(self._dateChanged)
self.stopDate.dateChanged.connect(self._dateChanged)
self.show()
def startup(self):
sys.exit(self.app.exec_())
def _textChanged(self):
self.setView()
def _dateChanged(self):
start = self.startDate.date()
end = self.stopDate.date()
self.start = dt.date(year=start.year(), month=start.month(), day=start.day())
self.stop = dt.date(year=end.year(), month=end.month(), day=end.day())
#print('self.start = {}, self.stop = {}'.format(self.start, self.stop))
self.setView()
def setData(self, data, start, end, pnCol, dateCol):
self.start = start
self.stop = end
self.model = PandasModel(data, pnCol, dateCol)
self.proxyModel = MyProxyModel(start, end)
self.proxyModel.setSourceModel(self.model)
self.tableView.setModel(self.proxyModel)
def setView(self):
text = self.inputBox.text()
pattern = "^" + text + ".*"
self.proxyModel.setFilterRegExp(QtCore.QRegExp(pattern))
self.proxyModel.setFilterKeyColumn(0)
self.proxyModel.setMinDate(self.start)
self.proxyModel.setMaxDate(self.stop)
class MyProxyModel(QtGui.QSortFilterProxyModel):
def __init__(self, minDate, maxDate):
super(MyProxyModel, self).__init__()
self.minDate = minDate
self.maxDate = maxDate
def filterAcceptsRow(self, row, parent):
#if self.sourceModel().rowCount() > 0:
#QtCore.pyqtRemoveInputHook()
#import pdb; pdb.set_trace()
pnIndex = self.sourceModel().index(row, self.sourceModel().pnCol, parent)
dateIndex = self.sourceModel().index(row, self.sourceModel().dateCol, parent)
if not (pnIndex.isValid() and dateIndex.isValid()):
return False
else:
text = self.sourceModel().data(pnIndex)
match = re.match(self.filterRegExp().pattern(), text)
goodPN = False
if match:
goodPN = True
goodDate = self.isValidDate(self.sourceModel().data(dateIndex))
return goodPN and goodDate
def setMinDate(self, date):
self.minDate = date
def setMaxDate(self, date):
self.maxDate = date
def isValidDate(self, date):
year, month, day = date.split('-')
date = dt.date(year=int(year), month=int(month), day=int(day))
valid = self.minDate <= date <= self.maxDate
#print('min = {}, max = {}, test = {}, valid = {}'.format(self.minDate, self.maxDate, date, valid))
return valid
class PandasModel(QtCore.QAbstractTableModel):
"""
Class to populate a table view with a pandas dataframe
Stolen from http://stackoverflow.com/questions/31475965/fastest-way-to-populate-qtableview-from-pandas-data-frame
"""
def __init__(self, data, pnCol, dateCol, parent=None):
QtCore.QAbstractTableModel.__init__(self, parent)
self._data = data
self.curRows = 0
self.totRows = len(self._data.values)
self.pnCol = pnCol
self.dateCol = dateCol
def canFetchMore(self, index):
"""
Note this and my fetchMore implementation were stolen from
https://riverbankcomputing.com/pipermail/pyqt/2009-May/022968.html
"""
if self.curRows < self.totRows:
return True
else:
return False
def fetchMore(self, index):
remainder = self.totRows - self.curRows
itemsToFetch = min(5, remainder)
self.beginInsertRows(QtCore.QModelIndex(), self.curRows, self.curRows+(itemsToFetch-1))
self.curRows += itemsToFetch
self.endInsertRows()
def rowCount(self, parent=None):
return self.curRows
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:
#QtCore.pyqtRemoveInputHook()
return str(self._data.iloc[index.row(), index.column()])
return None
def headerData(self, col, orientation, role):
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
return self._data.columns[col]
return None
def getRows(self, regexp):
out = []
col = self._data.columns.get_loc('_data')
for row in range(self.rowCount()):
check = self.data(self.index(row, col))
match = re.match(regexp, check)
if match:
out.append(row)
return out
if __name__ == "__main__":
myApp = MainWindow()
data = {'a':range(100),
'b':[str(chr(i+97))for i in range(10)]*10,
'_data':['abc', 'acd', 'ade', 'bcd', 'bde', 'bef', 'cde', 'cef', 'cfg', 'def']*10,
'c':['123', '456', '789', '101', '102', '103', '104', '105', '106', '107']*10,
'_dates':[dt.date(year=2016, month=1, day=i) for i in range(1, 20, 2)]*10}
data = pd.DataFrame(data)
start = dt.date(year=2016, month=1, day=1)
stop = dt.date(year=2016, month=1, day=15)
pnCol = data.columns.get_loc('_data')
dateCol = data.columns.get_loc('_dates')
myApp.setData(data, start, stop, pnCol, dateCol)
myApp.startup()
最终发生的事情是过滤器按预期工作,但是由于延迟加载,列表在我滚动之前大部分都是空的。
我认为在我rowCount
的{{1}}实施中,此错误的来源是第132行。在这里,我在Qt文档中返回PandasModel
而不是self.curRows
作为建议here如何实现延迟加载。具体来说,靠近页面底部self.totRows
所以,我的问题是如何在这里修改我的方法,以便我可以利用延迟加载和过滤?
更新:重新编写代码以解决一些错误,特别是我停止使用"Notice that the row count is only the items we have added so far, i.e., not the number of entries in the directory."
并实现了python的toString()
。还修了一些拼写错误。