I'm trying to create a custom TableModel class for QTableView. The cells containing 1 as data must have red outlining. Outlining is made by returning a pixmap (with red borders and text drawn on top) from TableModel instead of returning a simple string.
The problem is in the unexpected padding of the pixmap, which I return as DecorationRole. I checked if the pixmap is drawn correctly (and it actually is 21x21 px with well done outlining, without padding, just as planned) right before the return pixmap line.
Here is the right drawn pixmap, which was saved just before the return from TableModel:
Eventually, something shifts the returned pixmap by exactly 3px from the left border of the QTableView cell. I didn't set any padding in QtDesigner for the QTableView and didn't change it later in my code. I also tried to manually set up padding to zero using stylesheet, but it gave no different result.
Any ideas how to fix it? Thank you.
Here is the sample of my TableModel:
class TableModel(QtCore.QAbstractTableModel):
def __init__(self, topology=None):
super().__init__()
...
# Hardcode cell size and path to rectangle image
self.cell_width, self.cell_height = 21, 21
self.fpath_red_rect = './path/to/red_rect.png'
def rowCount(self, parent=QtCore.QModelIndex()):
return self.data.shape[0]
def columnCount(self, parent=QtCore.QModelIndex()):
return self.data.shape[1]
def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
...
def size(self):
return QtCore.QSize((self.columnCount() + 1) * self.cell_width,
(self.rowCount() + 1) * self.cell_height)
def data(self, index, role=QtCore.Qt.DisplayRole):
if not index.isValid():
return QtCore.QVariant()
i = index.row()
j = index.column()
if role == QtCore.Qt.DisplayRole:
if self.data[i, j] == 0: # empty
return ''
elif self.data[i, j] == 1: # cell with red rectangle
# the text will be drawn on pixmap manually later
return None
else:
return '{0}'.format(self.data[i, j]) # display default data
if role == QtCore.Qt.DecorationRole:
# Create pixmap, draw the rectangle on it and then draw text on top
pixmap = QtGui.QPixmap(self.cell_width, self.cell_height)
image = QtGui.QImage(self.fpath_red_rect).scaled(self.cell_width, self.cell_height)
painter = QtGui.QPainter(pixmap)
painter.drawImage(pixmap.rect().topLeft(), image)
painter.drawText(pixmap.rect(), QtCore.Qt.AlignCenter, '{0}'.format(self.data[i, j]))
painter.end()
# If we save the pixmap to PNG image here (see the link above),
# we get the expected 21 x 21 px image, with nice
# and properly drawn rectangle and centered text.
# But something goes wrong after returning
return pixmap
if role == QtCore.Qt.BackgroundRole:
return QtGui.QBrush(self.getQtColor(self.data[i, j]))
if role == QtCore.Qt.TextAlignmentRole:
return QtCore.Qt.AlignCenter
return QtCore.QVariant()
DecorationRole is used to draw the icon for that reason you observe the displacement, in your case you should not use that role, besides the painting task should not be done in the model since he only has to provide the data, if you want to modify the drawing a better option is use a delegate as I show below:
import sys
import numpy as np
from PyQt5 import QtCore, QtGui, QtWidgets
ValueRole = QtCore.Qt.UserRole + 1
max_val = 4
colors = [QtGui.QColor(*np.random.randint(255, size=3)) for i in range(max_val)]
class TableModel(QtCore.QAbstractTableModel):
def __init__(self, parent=None):
QtCore.QAbstractTableModel.__init__(self, parent)
self.data = np.random.randint(max_val, size=(10, 10))
def rowCount(self, parent=QtCore.QModelIndex()):
return self.data.shape[0]
def columnCount(self, parent=QtCore.QModelIndex()):
return self.data.shape[1]
def data(self, index, role=QtCore.Qt.DisplayRole):
if not index.isValid():
return QtCore.QVariant()
i = index.row()
j = index.column()
val = self.data[i, j]
if role == QtCore.Qt.DisplayRole:
return str(val)
elif role == QtCore.Qt.TextAlignmentRole:
return QtCore.Qt.AlignCenter
elif role == QtCore.Qt.BackgroundRole:
return colors[val]
if role == ValueRole:
return val
return QtCore.QVariant()
class Delegate(QtWidgets.QStyledItemDelegate):
def paint(self, painter, option, index):
QtWidgets.QStyledItemDelegate.paint(self, painter, option, index)
if index.data(ValueRole) == 1:
painter.save()
pen = painter.pen()
pen.setColor(QtCore.Qt.red)
painter.setPen(pen)
r = QtCore.QRect(option.rect)
r.adjust(0, 0, -pen.width(), -pen.width())
painter.drawRect(r)
painter.restore()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = QtWidgets.QTableView()
w.setItemDelegate(Delegate(w))
model = TableModel()
w.setModel(model)
w.verticalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Fixed)
w.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Fixed)
for i in range(model.rowCount()):
w.verticalHeader().resizeSection(i, 21)
for j in range(model.columnCount()):
w.horizontalHeader().resizeSection(j, 21)
w.show()
sys.exit(app.exec_())
Related
how i can show a loading GIF image or a Qlabel update while i load data from database with QAbstractTableModel.i am new in pyqt5 and i tried it from last week but didn't understand how i can do that .
there are many example i found in stackoverflow but i really cannot deal with Qthread.i don't want to use timer for it as i can see in many examples are using qtimer. loading gif is automatically close while loading completed in table.
can anyone please show me how to do this and describes all things.
from PyQt5 import QtCore, QtWidgets
import pandas as pd
import numpy as np
import pyodbc
class NumpyArrayModel(QtCore.QAbstractTableModel):
def __init__(self, array, headers, parent=None):
QtCore.QAbstractTableModel.__init__(self, parent=parent)
self._array = array
self._headers = headers
self.r, self.c = np.shape(self.array)
#property
def array(self):
return self._array
#property
def headers(self):
return self._headers
def rowCount(self, parent=QtCore.QModelIndex()):
return self.r
def columnCount(self, parent=QtCore.QModelIndex()):
return self.c
def headerData(self, p_int, orientation, role):
if role == QtCore.Qt.DisplayRole:
if orientation == QtCore.Qt.Horizontal:
if p_int < len(self.headers):
return self.headers[p_int]
elif orientation == QtCore.Qt.Vertical:
return p_int + 1
return
def data(self, index, role=QtCore.Qt.DisplayRole):
if not index.isValid():
return None
row = index.row()
column = index.column()
if row < 0 or row >= self.rowCount():
return None
if column < 0 or column >= self.columnCount():
return None
if role == QtCore.Qt.DisplayRole:
return str(self.array[row, column])
return None
def setData(self, index, value, role):
if not index.isValid():
return False
if role != QtCore.Qt.EditRole:
return False
row = index.row()
column = index.column()
if row < 0 or row >= self.rowCount():
return False
if column < 0 or column >= self.columnCount():
return False
self.array.values[row][column] = value
self.dataChanged.emit(index, index)
return True
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent=None)
vLayout = QtWidgets.QVBoxLayout(self)
hLayout = QtWidgets.QHBoxLayout()
self.pathLE = QtWidgets.QLabel(self)
hLayout.addWidget(self.pathLE)
self.loadBtn = QtWidgets.QPushButton("Load data", self)
hLayout.addWidget(self.loadBtn)
vLayout.addLayout(hLayout)
self.pandasTv = QtWidgets.QTableView(self)
vLayout.addWidget(self.pandasTv)
self.loadBtn.clicked.connect(self.loadFile)
self.pandasTv.setSortingEnabled(True)
def loadFile(self):
self.pathLE.setText("Loading data")
server = '190.11.71.09'
database = ''
username = 'Admin'
passwd = ''
conn= pyodbc.connect('DRIVER={ODBC Driver 17 for SQL Server};SERVER=' +
server+';DATABASE='+database+';UID='+username+';PWD=' + passwd)
query="select * from database.dbo.tableName(nolock)"
df = pd.read_sql_query(query, conn)
array = np.array(df.values)
headers = df.columns.tolist()
model = NumpyArrayModel(array, headers)
self.pandasTv.setModel(model)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
Learn how to display a GIF image.
Then learn how to trigger an action via a button.
Do not fall into the typical pit by implementing your action to
display the GIF
load the data
hide the GIF
as this ties down the one thread that triggered your action. This one thread is crucial to keep the UI updating.
So what you need to do when the button gets pressed:
Spawn a new thread to execute some code
In the new thread the code to execute contains the above statements:
show GIF
load data
hide GIF (even if data loading fails)
For showing, hiding and finally rendering the loaded data you will have to look out because now you try to modify the UI from another thread - this will need some kind of treatment. BTW this behaviour is not specific to Qt. You will find similar things in Java AWT and Swing.
Consider this example, modified from QStyledItemDelegate paint refresh issues :
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class MyElement(object):
def __init__(self, numid):
self.numid = numid
self.strid = "Hello world {}".format(numid)
self.param = 'a' if numid%2==0 else 'b'
def __repr__(self):
return "(numid {}, strid '{}', param '{}')".format(self.numid, self.strid, self.param)
elements = [ MyElement(i) for i in range(20) ]
print(elements)
class ElementListModel(QtCore.QAbstractListModel):
def __init__(self, elements = [], parent = None):
super(ElementListModel, self).__init__()
self.__elements = elements
def rowCount(self, parent):
return len(self.__elements)
def data(self, index, role):
thiselement = self.__elements[index.row()]
if role == QtCore.Qt.DisplayRole:
return str( thiselement.strid )
elif role == QtCore.Qt.DecorationRole:
return QtGui.QColor(thiselement.numid*10,thiselement.numid,0)
class ElementThumbDelegate(QtWidgets.QStyledItemDelegate): #(QtGui.QStyledItemDelegate):
def __init__(self, view, parent=None):
super(ElementThumbDelegate, self).__init__(parent)
def paint(self, painter, options, index):
super(ElementThumbDelegate, self).paint(painter, options, index)
#painter.setRenderHint(QtGui.QPainter.Antialiasing)
#painter.setPen(QtGui.QColor(255, 255, 255))
#painter.setBrush(QtGui.QColor(10, 10, 10))
#painter.drawRect(options.rect)
#painter.drawText(options.rect, QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter, str(index.data()))
#def sizeHint(self, options, index):
# return QtCore.QSize(50, 50)
def main():
app = QtWidgets.QApplication(sys.argv)
viewer = QtWidgets.QListView()
viewModel = ElementListModel(elements)
viewer.setModel(viewModel)
#viewer.setViewMode(QtWidgets.QListView.IconMode)
viewer.setItemDelegate(ElementThumbDelegate(viewer))
viewer.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
It results with this:
Note that there is a box by default to the left of the item, which you can "color" via DecorationRole in the data method of the ListModel (and apparently, you can also store an icon there, if you return a QIcon instead of QColor, but I've never tried it).
My question is:
How can I draw a border around that icon space/box, depending on some property? In the example above, if MyElement.param == 'a' of a given element in the list, then I would want a light blue (RGB: (38, 76, 100), or #62c2ff) border of width 2 pixels drawn around the "icon space/box" - just like I've manually done in the mockup image in the circled area; otherwise I would not want a border
How could I additionally draw a single letter in the center of that space/box, depending on some property? For instance, if a MyElement.param == 'b' of a given element in the list, then I'd like the letter 'b' written in white in the middle of the "icon space/box" - otherwise, I would not want an extra text written in that space.
The paint() method of ElementThumbDelegate should have otherwise been enough of a pointer on how to do this; but if you uncomment it, you'll see the entire item is changed - not just the left icon box/space.
The class that performs the painting is the delegate who takes the information from the DecorationRole role to create the icon, so the solution is to create the custom icon depending on the item information. That creation can be done in the model or in the delegate, in this case I will use the second option but for this the item must be exposed through a custom role like Qt.UserRole:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class MyElement(object):
def __init__(self, numid):
self.numid = numid
self.strid = "Hello world {}".format(numid)
self.param = "a" if numid % 2 == 0 else "b"
def __repr__(self):
return "(numid {}, strid '{}', param '{}')".format(
self.numid, self.strid, self.param
)
elements = [MyElement(i) for i in range(20)]
class ElementListModel(QtCore.QAbstractListModel):
def __init__(self, elements=[], parent=None):
super(ElementListModel, self).__init__()
self.__elements = elements
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.__elements)
def data(self, index, role):
if not index.isValid() or not (0 <= index.row() < self.rowCount()):
return
thiselement = self.__elements[index.row()]
if role == QtCore.Qt.DisplayRole:
return str(thiselement.strid)
if role == QtCore.Qt.UserRole:
return thiselement
class ElementThumbDelegate(QtWidgets.QStyledItemDelegate):
def initStyleOption(self, option, index):
super().initStyleOption(option, index)
thiselement = index.data(QtCore.Qt.UserRole)
if isinstance(thiselement, MyElement):
if thiselement.param == "a":
option.features |= QtWidgets.QStyleOptionViewItem.HasDecoration
pixmap = QtGui.QPixmap(option.decorationSize)
pixmap.fill(QtGui.QColor("#62c2ff"))
painter = QtGui.QPainter(pixmap)
color = QtGui.QColor(thiselement.numid * 10, thiselement.numid, 0)
painter.fillRect(pixmap.rect().adjusted(2, 2, -2, -2), color)
painter.end()
option.icon = QtGui.QIcon(pixmap)
if thiselement.param == "b":
option.features |= QtWidgets.QStyleOptionViewItem.HasDecoration
pixmap = QtGui.QPixmap(option.decorationSize)
color = QtGui.QColor(thiselement.numid * 10, thiselement.numid, 0)
pixmap.fill(color)
painter = QtGui.QPainter(pixmap)
painter.setPen(QtGui.QColor("white"))
painter.drawText(pixmap.rect(), QtCore.Qt.AlignCenter, "b")
painter.end()
option.icon = QtGui.QIcon(pixmap)
def main():
app = QtWidgets.QApplication(sys.argv)
viewer = QtWidgets.QListView()
viewModel = ElementListModel(elements)
viewer.setModel(viewModel)
viewer.setItemDelegate(ElementThumbDelegate(viewer))
viewer.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
I need a QTableWidget based on a QTabelModel and QTableView with some buttons added above the table. See the following figure:
The width of the QTableWidget should be adjusted so that it is not smaller than a reasonable minimum and not extend beyond the buttons above it; in particular, the size of the columns 1, 2, and 4 should be adjusted to their contents, and the 3rd column, Aberrations, should be expanded to fill in the gap on the right side. I'd like to know how to do this in code.
The following is a minimal example of the code I use for the custom QTableWidget (PyQt5, Python3):
from PyQt5 import QtGui, QtCore, QtWidgets
import numpy as np
#-- Table Model
class MyTableModel(QtCore.QAbstractTableModel):
def __init__(self, data, parent=None, *args):
super(MyTableModel, self).__init__(parent)
# table data
self.table_data = data
self.rows_nr, self.columns_nr = data.shape
# vertical & horizontal header labels
self.hheaders = ["Head-{}".format(i) for i in range(self.columns_nr)]
self.vheaders = ["Row-{}".format(i) for i in range(self.rows_nr)]
# nr of rows
def rowCount(self, parent):
return self.rows_nr
# nr of columns
def columnCount(self, parent):
return self.columns_nr
# row and column headers
def headerData(self, section, orientation, role):
if role == QtCore.Qt.DisplayRole:
if orientation == QtCore.Qt.Horizontal:
return self.hheaders[section]
#END if
#ELSE:
return QtCore.QVariant()
# display table contents
def data(self, index, role=QtCore.Qt.DisplayRole):
r_ = index.row()
c_ = index.column()
if role == QtCore.Qt.DisplayRole:
return "{}".format(data[r_, c_])
#ELSE:
return QtCore.QVariant()
# set data
def setData(self, index, value, role):
r_ = index.row()
c_ = index.column()
# editable fields
if role == QtCore.Qt.EditRole:
# interprete values
self.table_data[r_,c_] = str(value)
return True
# view/edit flags
def flags(self, index):
r_ = index.row()
c_ = index.column()
return QtCore.Qt.ItemIsEnabled
class MyTableWidget(QtWidgets.QWidget):
def __init__(self, data, *args):
super(MyTableWidget, self).__init__(*args)
#-- table model
tablemodel = MyTableModel(data=data, parent=self)
#-- table view
tableview = QtWidgets.QTableView()
tableview.setModel(tablemodel)
tableview.verticalHeader().hide() # hide vertical/row headers
# size policy
tableview.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
tableview.setSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
#-- layouts
#--- buttons
button_hlayout = QtWidgets.QHBoxLayout()
button_hlayout.addWidget(QtWidgets.QPushButton("Button 1"))
button_hlayout.addWidget(QtWidgets.QPushButton("Button 2"))
button_hlayout.addWidget(QtWidgets.QPushButton("Button 3"))
#--- table
table_layout = QtWidgets.QVBoxLayout()
table_layout.addLayout(button_hlayout)
table_layout.addWidget(tableview)
self.setLayout(table_layout)
#----------------------------------------
#-- produce sample data
data = np.empty(shape=(3,4), dtype=np.object)
for r in range(3):
for c in range(4):
data[r,c] = str(list(range((r+1) * (c+1))))
app = QtWidgets.QApplication([""])
w = MyTableWidget(data=data)
w.show()
app.exec_()
void QHeaderView::setSectionResizeMode(int logicalIndex, QHeaderView::ResizeMode mode)
Sets the constraints on how the section specified by logicalIndex in the header can be resized to those described by the given mode. The logical index should exist at the time this function is called.
from PyQt5 import QtGui, QtCore, QtWidgets
import numpy as np
#-- Table Model
class MyTableModel(QtCore.QAbstractTableModel):
def __init__(self, data, parent=None, *args):
super(MyTableModel, self).__init__(parent)
# table data
self.table_data = data
self.rows_nr, self.columns_nr = data.shape
# vertical & horizontal header labels
self.hheaders = ["Head-{}".format(i) for i in range(self.columns_nr)]
self.vheaders = ["Row-{}".format(i) for i in range(self.rows_nr)]
# nr of rows
def rowCount(self, parent):
return self.rows_nr
# nr of columns
def columnCount(self, parent):
return self.columns_nr
# row and column headers
def headerData(self, section, orientation, role):
if role == QtCore.Qt.DisplayRole:
if orientation == QtCore.Qt.Horizontal:
return self.hheaders[section]
#END if
#ELSE:
return QtCore.QVariant()
# display table contents
def data(self, index, role=QtCore.Qt.DisplayRole):
r_ = index.row()
c_ = index.column()
if role == QtCore.Qt.DisplayRole:
return "{}".format(data[r_, c_])
#ELSE:
return QtCore.QVariant()
# set data
def setData(self, index, value, role):
r_ = index.row()
c_ = index.column()
# editable fields
if role == QtCore.Qt.EditRole:
# interprete values
self.table_data[r_,c_] = str(value)
return True
# view/edit flags
def flags(self, index):
r_ = index.row()
c_ = index.column()
return QtCore.Qt.ItemIsEnabled
class MyTableWidget(QtWidgets.QWidget):
def __init__(self, data, *args):
super(MyTableWidget, self).__init__(*args)
#-- table model
tablemodel = MyTableModel(data=data, parent=self)
#-- table view
tableview = QtWidgets.QTableView()
tableview.setModel(tablemodel)
tableview.verticalHeader().hide() # hide vertical/row headers
#-- +++
tableview.setAlternatingRowColors(True)
tableview.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Stretch)
tableview.horizontalHeader().setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeToContents)
tableview.horizontalHeader().setSectionResizeMode(1, QtWidgets.QHeaderView.ResizeToContents)
tableview.horizontalHeader().setSectionResizeMode(3, QtWidgets.QHeaderView.ResizeToContents)
# size policy
tableview.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
#tableview.setSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) # ---
tableview.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)# +++
#-- layouts
#--- buttons
button_hlayout = QtWidgets.QHBoxLayout()
button_hlayout.addWidget(QtWidgets.QPushButton("Button 1"))
button_hlayout.addWidget(QtWidgets.QPushButton("Button 2"))
button_hlayout.addWidget(QtWidgets.QPushButton("Button 3"))
#--- table
table_layout = QtWidgets.QVBoxLayout()
table_layout.addLayout(button_hlayout)
table_layout.addWidget(tableview)
self.setLayout(table_layout)
#----------------------------------------
#-- produce sample data
data = np.empty(shape=(3,4), dtype=np.object)
for r in range(3):
for c in range(4):
data[r,c] = str(list(range((r+1) * (c+1))))
app = QtWidgets.QApplication([""])
w = MyTableWidget(data=data)
w.show()
app.exec_()
In the code above, tableview.horizontalHeader().SetSectionResizeMode(QtWidgets.QHeaderView.Stretch) applies the Stretch mode to all columns, and the remaining 3 operators set the corresponding columns to the ResizeToContents mode.
The resizing behaviour of the widget window is determined by setSizePolicy method. In this case, the policy can be also tableview.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum), which allows the user to enlarge or shrink the widget window.
The code below creates a single QTableView linked to QAbstractTableModel with three columns:
To assign a horizontal red-blue gradient to the items in the last column I create a gradient with
gradient = QtGui.QLinearGradient(0, 0, COLUMN_WIDTH, 0)
In order to divide the gradient in half (one painted red and another blue) I need to supply
QLinearGradient with the exact COLUMN_WIDTH value.
How to get COLUMN_WIDTH?
from PyQt4 import QtCore, QtGui
app = QtGui.QApplication([])
class Model(QtCore.QAbstractTableModel):
def __init__(self, parent=None):
super(Model, self).__init__(parent)
self.items = [['Row%s Col%s'%(row,col) for col in range(3)] for row in range(5)]
def rowCount(self, parent=None):
return len(self.items)
def columnCount(self, parent=None):
return len(self.items[0])
def data(self, index, role=QtCore.Qt.DisplayRole):
row = index.row()
column = index.column()
if role == QtCore.Qt.DisplayRole:
if 0 <= row < self.rowCount() and 0 <= column < self.columnCount():
return self.items[row][column]
if role == QtCore.Qt.BackgroundRole and column==2:
COLUMN_WIDTH = 50
gradient = QtGui.QLinearGradient(0, 0, COLUMN_WIDTH, 0)
gradient.setColorAt(0.5, QtGui.QColor('red'))
gradient.setColorAt(0.5001, QtGui.QColor('blue'))
brush = QtGui.QBrush(gradient)
return brush
view = QtGui.QTableView()
model = Model(view)
view.setModel(model)
view.show()
app.exec_()
columnWidth() is a property of QTableView:
COLUMN_WIDTH = self.parent().columnWidth(index.column())
I have a QTableView with three columns
The second column is about numbers, there are only three types: 1, -1 and 0.
I want to have different colors for this three "types" of numbers (1,-1,0), coloring their rows with different colors. How can i do it?
self.tableView = QTableView(self.tabSentimento)
self.tableView.setGeometry(QRect(550,10,510,700))
self.tableView.setObjectName(_fromUtf8("TabelaSentimento"))
self.tableView.setModel(self.model)
self.tableView.horizontalHeader().setStretchLastSection(True)
obs: I used horizontalheader().setStrechLastSection(True) because I opened an existing csv file (using a button) into my tableview.
You have to define the color in the model, not in the view:
def data(self, index, role):
...
if role == Qt.BackgroundRole:
return QBrush(Qt.yellow)
Edit:
Here's a working example, except for the color part completely stolen from http://www.saltycrane.com/blog/2007/06/pyqt-42-qabstracttablemodelqtableview/
from PyQt4.QtCore import *
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys
my_array = [['00','01','02'],
['10','11','12'],
['20','21','22']]
def main():
app = QApplication(sys.argv)
w = MyWindow()
w.show()
sys.exit(app.exec_())
class MyWindow(QTableView):
def __init__(self, *args):
QTableView.__init__(self, *args)
tablemodel = MyTableModel(my_array, self)
self.setModel(tablemodel)
class MyTableModel(QAbstractTableModel):
def __init__(self, datain, parent=None, *args):
QAbstractTableModel.__init__(self, parent, *args)
self.arraydata = datain
def rowCount(self, parent):
return len(self.arraydata)
def columnCount(self, parent):
return len(self.arraydata[0])
def data(self, index, role):
if not index.isValid():
return QVariant()
# vvvv this is the magic part
elif role == Qt.BackgroundRole:
if index.row() % 2 == 0:
return QBrush(Qt.yellow)
else:
return QBrush(Qt.red)
# ^^^^ this is the magic part
elif role != Qt.DisplayRole:
return QVariant()
return QVariant(self.arraydata[index.row()][index.column()])
if __name__ == "__main__":
main()