Может ли кто-нибудь объяснить следующее: У меня есть 2 скрипта для загрузки кадра данных pandas в табличном представлении с полем фильтра. Тот, что со стандартной моделью, загружает данные в раздел «init». С этим все молниеносно, даже фильтрация. Второй скрипт работает намного медленнее, но с ним я могу установить цвет фона ячеек, который мне нужен. Это скрипты:
import timeit
import pandas as pd
from PyQt5 import QtGui
from PyQt5 import QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtCore import QAbstractTableModel
from PyQt5.QtCore import Qt, QSortFilterProxyModel
from PyQt5.QtGui import *
from PyQt5.uic import loadUi
class PandasTableModel(QtGui.QStandardItemModel):
def __init__(self, data, parent=None):
QtGui.QStandardItemModel.__init__(self, parent)
self._data = data
for col in data.columns:
data_col = [QtGui.QStandardItem("{}".format(x)) for x in data[col].values]
self.appendColumn(data_col)
return
def rowCount(self, parent=None):
return len(self._data.values)
def columnCount(self, parent=None):
return self._data.columns.size
def headerData(self, x, orientation, role):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self._data.columns[x]
if orientation == Qt.Vertical and role == Qt.DisplayRole:
return self._data.index[x]
def flags(self, index):
if not index.isValid():
return Qt.ItemIsEnabled
return super().flags(index) | Qt.ItemIsEditable # add editable flag.
def setData(self, index, value, role):
if role == Qt.EditRole:
# Set the value into the frame.
self._data.iloc[index.row(), index.column()] = value
return True
return False
class TableViewer(QtWidgets.QMainWindow):
def __init__(self):
super(TableViewer, self).__init__()
self.ui = loadUi("QTableViewForm.ui", self)
self.ui.cmdRun1.clicked.connect(self.RunFunction1)
self.ui.cmdRun2.clicked.connect(self.RunFunction2)
self.ui.inputFilter.textChanged.connect(self.SetFilteredView)
self.showdata()
def showdata(self):
start = timeit.default_timer()
print("Start LoadData")
data = pd.read_pickle("productdata.pkl")
self.model = PandasTableModel(data)
self.ui.tableData.setModel(self.model)
self.proxy_model = QSortFilterProxyModel()
self.proxy_model.setFilterKeyColumn(-1) # Search all columns.
self.proxy_model.setSourceModel(self.model)
self.proxy_model.sort(0, Qt.AscendingOrder)
self.proxy_model.setFilterCaseSensitivity(False)
self.ui.tableData.setModel(self.proxy_model)
print("Stop LoadData")
end = timeit.default_timer()
print("Process Time: ", (end - start))
def set_cell_color(self, row, column):
self.model.change_color(row, column, QBrush(Qt.red))
def RunFunction1(self):
start = timeit.default_timer()
print("Start RunFunction1")
#Gans de rij in 't rood
colums = self.proxy_model.columnCount()
for c in range(colums):
self.set_cell_color(3, c)
print("Stop RunFunction1")
end = timeit.default_timer()
print("Process Time: ", (end - start))
def RunFunction2(self):
start = timeit.default_timer()
print("Start RunFunction1")
#Gans de rij in 't rood
colums = self.proxy_model.columnCount()
for c in range(colums):
self.set_cell_color(3, c)
print("Stop RunFunction1")
end = timeit.default_timer()
print("Process Time: ", (end - start))
def SetFilteredView(self):
# print("Start set_filter")
filter_text = self.ui.inputFilter.text()
self.proxy_model.setFilterFixedString(filter_text)
filter_result = self.proxy_model.rowCount()
self.ui.lblResult.setText("(" + str(filter_result) + " records)")
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
win = TableViewer()
win.show()
sys.exit(app.exec_())enter code here
И медленный:
import timeit
import pandas as pd
from PyQt5 import QtGui
from PyQt5 import QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtCore import QAbstractTableModel
from PyQt5.QtCore import Qt, QSortFilterProxyModel
from PyQt5.QtGui import *
from PyQt5.uic import loadUi
class PandasTableModel(QAbstractTableModel):
def __init__(self, data, parent=None):
QAbstractItemModel.__init__(self, parent)
self._data = data
self.colors = dict()
def rowCount(self, parent=None):
return self._data.index.size
def columnCount(self, parent=None):
return self._data.columns.size
def setData(self, index, value, role):
if role == Qt.EditRole:
# Set the value into the frame.
self._data.iloc[index.row(), index.column()] = value
return True
def data(self, index, role=Qt.DisplayRole):
if index.isValid():
if role == Qt.DisplayRole:
return str(self._data.iloc[index.row(), index.column()])
if role == Qt.EditRole:
return str(self._data.iloc[index.row(), index.column()])
if role == Qt.BackgroundRole:
color = self.colors.get((index.row(), index.column()))
if color is not None:
return color
return None
def headerData(self, rowcol, orientation, role):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self._data.columns[rowcol]
if orientation == Qt.Vertical and role == Qt.DisplayRole:
return self._data.index[rowcol]
return None
def change_color(self, row, column, color):
ix = self.index(row, column)
self.colors[(row, column)] = color
self.dataChanged.emit(ix, ix, (Qt.BackgroundRole,))
class TableViewer(QtWidgets.QMainWindow):
def __init__(self):
super(TableViewer, self).__init__()
self.ui = loadUi("QTableViewForm.ui", self)
self.ui.cmdRun1.clicked.connect(self.RunFunction1)
self.ui.cmdRun2.clicked.connect(self.RunFunction2)
self.ui.inputFilter.textChanged.connect(self.SetFilteredView)
self.showdata()
def showdata(self):
start = timeit.default_timer()
print("Start LoadData")
data = pd.read_pickle("productdata.pkl")
self.model = PandasTableModel(data)
self.ui.tableData.setModel(self.model)
self.proxy_model = QSortFilterProxyModel()
self.proxy_model.setFilterKeyColumn(-1) # Search all columns.
self.proxy_model.setSourceModel(self.model)
self.proxy_model.sort(0, Qt.AscendingOrder)
self.proxy_model.setFilterCaseSensitivity(False)
self.ui.tableData.setModel(self.proxy_model)
print("Stop LoadData")
end = timeit.default_timer()
print("Process Time: ", (end - start))
def set_cell_color(self, row, column):
self.model.change_color(row, column, QBrush(Qt.red))
def RunFunction1(self):
start = timeit.default_timer()
print("Start RunFunction1")
#Gans de rij in 't rood
colums = self.proxy_model.columnCount()
for c in range(colums):
self.set_cell_color(3, c)
print("Stop RunFunction1")
end = timeit.default_timer()
print("Process Time: ", (end - start))
def RunFunction2(self):
start = timeit.default_timer()
print("Start RunFunction1")
#Gans de rij in 't rood
colums = self.proxy_model.columnCount()
for c in range(colums):
self.set_cell_color(3, c)
print("Stop RunFunction1")
end = timeit.default_timer()
print("Process Time: ", (end - start))
def SetFilteredView(self):
# print("Start set_filter")
filter_text = self.ui.inputFilter.text()
self.proxy_model.setFilterFixedString(filter_text)
filter_result = self.proxy_model.rowCount()
self.ui.lblResult.setText("(" + str(filter_result) + " records)")
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
win = TableViewer()
win.show()
sys.exit(app.exec_())
(я загружаю 2000 строк и 35 столбцов)
Могу ли я получить быструю версию с функцией цвета фона?
Привет, Джонсон
Если бы это было так просто, было бы здорово ;-) Могу ли я сделать это для определенной ячейки или строки? Можете ли вы привести пример синтаксиса?
Хорошо, я добавил этот код к ответу. Кстати. Странно, что модель, унаследованная от QAbstractTableModel
, как вы говорите, медленнее. Я бы ожидал обратного, чтобы быть правдой. Возможно, это имеет место только в Python, где больше кода вызывается в Python и меньше в базовой библиотеке C++.
Вместо
def set_cell_color(self, row, column):
self.model.change_color(row, column, QBrush(Qt.red))
использовать это
def set_cell_color(self, row, column):
self.model.item(row, column).setBackground(QBrush(Qt.red))
В зависимости от ваших требований вам может потребоваться заменить model
на proxy_model
, но это зависит от того, должны ли строка и столбец ссылаться на координаты отфильтрованной или базовой модели. Так что это зависит от вас.
Это было действительно так просто... Большое спасибо!
Готово ! Еще раз спасибо, вы не хотите знать, сколько времени я трачу на поиски в неправильном направлении ... ;-)
Мне знакомо это чувство... :)
Может быть, я неправильно понял проблему, но почему бы вам не установить цвет фона с помощью doc.qt.io/qt-5/qstandarditem.html#setBackground для стандартной модели?