'Setting background on Qtableview using a function
IU have a Qt window with a button and a QTableView which loads some data from a pandas dataframe using the QAbstractTableModel. I would like to set the backgroundcolor of a cel (or a row) when i click on the button.
This is my code so far:
import timeit
import pandas as pd
from PyQt5 import QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtCore import QAbstractTableModel, Qt
from PyQt5.QtGui import *
from PyQt5.uic import loadUi
class PandasModel(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 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 flags(self, index):
flags = super(self.__class__, self).flags(index)
flags |= Qt.ItemIsEditable
flags |= Qt.ItemIsSelectable
flags |= Qt.ItemIsEnabled
flags |= Qt.ItemIsDragEnabled
flags |= Qt.ItemIsDropEnabled
return flags
def sort(self, Ncol, order):
"""Sort table by given column number.
"""
try:
self.layoutAboutToBeChanged.emit()
self._data = self._data.sort_values(self._data.columns[Ncol], ascending=not order)
self.layoutChanged.emit()
except Exception as e:
print(e)
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.showdata()
def showdata(self):
data = pd.read_pickle("productdata.pkl")
self.model = PandasModel(data)
self.ui.tableData.setModel(self.model)
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")
print("Stop RunFunction1")
end = timeit.default_timer()
print("Process Time: ", (end - start))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
win = TableViewer()
win.set_cell_color(row=7,column=7)
win.show()
sys.exit(app.exec_())
When i run this i get cell (7,7) with a red background. Now i would like to do this by clicking the button and running the function Run Function1 but i can't get this to work.
Solution 1:[1]
Got it working , i just go over the row to get it in color. I'm working a lot with dataframes so if annyone has any suggestions to complete the PandasModel(QAbstractTableModel) class feel free ;-)
Updated Code:
import timeit
import pandas as pd
from PyQt5 import QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtCore import QAbstractTableModel, Qt
from PyQt5.QtGui import *
from PyQt5.uic import loadUi
class PandasModel(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.showdata()
def showdata(self):
data = pd.read_pickle("productdata.pkl")
self.model = PandasModel(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.tableData.setModel(self.proxy_model)
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))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
win = TableViewer()
win.show()
sys.exit(app.exec_())
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Ryan M |