What is "role" and where it comes from? (How to change background color after editing QTableView cell?)

StackOverflow https://stackoverflow.com/questions/20298529

  •  06-08-2022
  •  | 
  •  

سؤال

im trying to change the background color of a qtable cell after editing it. i already watched the qustion "How to change background color after editing QTableView cell?", the problem i have is, in the example from the answer, i dont understand where "role" comes from. i mean, where is role declared and where role change its value? i only see where role is compared to "Qt.Core.xxx"

import sys
from PyQt4 import QtGui, QtCore

class Model(QtCore.QAbstractTableModel):
    def __init__(self, parent=None):
        super(Model, self).__init__(parent)

    # list of lists containing [data for cell, changed]
    self._data = [[['%d - %d' % (i, j), False] for j in range(10)] for i in range(10)]

    def rowCount(self, parent):
        return len(self._data)

    def columnCount(self, parent):
        return len(self._data[0])

    def flags(self, index):
        return QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled |QtCore.Qt.ItemIsEditable

    def data(self, index, role):
        if index.isValid():
            data, changed = self._data[index.row()][index.column()]

        if role in [QtCore.Qt.DisplayRole, QtCore.Qt.EditRole]:
            return data

        if role == QtCore.Qt.BackgroundRole and changed:
            return QtGui.QBrush(QtCore.Qt.darkBlue)

    def setData(self, index, value, role):
        if role == QtCore.Qt.EditRole:
            # set the new value with True `changed` status
            self._data[index.row()][index.column()] = [value.toString(), True]
            self.dataChanged.emit(index, index)
            return True
    return False

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)

t = QtGui.QTableView()
m = Model(t)
t.setModel(m)
t.show()

sys.exit(app.exec_())

i cant just add a comment in the other question, because i dont have 50 "repution-points", sry.

هل كانت مفيدة؟

المحلول

It's the part of QAbstractItemModel interface. See:

If you'd like to learn more about Qt Model/View(/Controller) approach, there is also a tutorial:

Edit (a little program explanation):

Well, obviously you created an implementation QAbstractTableModel which has a little bit more specialized interface than QAbstractItemModel. It's "abstract", so it means that you have to provide a working implementation. On the other hand it already implements some of QAbstractItemModel methods, like createIndex(). Your model implementation is used internally by Qt when accessing informations about your table.

The most important methods are data() for data access and setData() for changing the data. Your data is a two-dimensional array of pairs: [string, bool]. The first element is the text that you displayed in table cell and the second element is a property holding information whether that specific element has been changed.

Those methods are usually called by Qt, e.g. when you edit a cell, move your mouse over widget, etc. For example, if hold your mouse over a table cell for a few moments, Qt will call data(cellIndex, QtCore.Qt.TooltipRole) so you'll be able to display a tooltip text. So in this case roles reflect activities or actions that user has taken. Like docs say:

Each item in the model has a set of data elements associated with it, each with its own role. The roles are used by the view to indicate to the model which type of data it needs. Custom models should return data in these types.

You don't have to serve all data roles. You can simply return QVariant() in C++ or None in Python (Python doesn't really need something like QVariant because it's dynamically typed). Remember that when you reach end of function in Python and don't return anything, Python will return None by default.

There is also flags() method which tells Qt what actions user will be available to do. Remove QtCore.Qt.ItemIsEditable and you won't be able to edit your table. A little trick here is that those flags have int values that are powers of 2. This way they can be easily OR-ed (sorry if it's not the correct verb for bitwise OR ;)) and returned as a single integer.

So when you for example double click cell, Qt first checks flags(). If QtCore.Qt.ItemIsEditable is set, it changes that cell to text area in which you can type a new value. If you leave it (e.g. by pressing Enter or selecting a another cell), it will call setData(cellIndex, typedString, Qt.EditRole) on your model. Moreover, setData() emits a signal which informs a View when data has been changed and that it should refresh data that it is displaying.

This approach gives us a separation of data controller and data viewer. Model doesn't know how data is displayed by views that use it (there might be more than one and they will be synchronised all the time). It's called MVC - Model/View/Controller. Unfortunately, Qt naming for its MVC implementation is misleading, but about it you can read more e.g. here.

Well, this response became a little too long but I hope that it's at least a little help for you. Good luck! :)

نصائح أخرى

A role is an ID used either by yourself, or the internals of Qt, to access a representation or meta-data for a given piece of data. For instance, if you piece of data is a colour, this colour could be represented as a string (the name of the colour) or as the colour itself (eg #123456).

The role allows you (or Qt) to choose which representation of the data should be returned.

Another potential use is to store information about the tooltip, backgound or foreground colour used when rendering the piece of data in your view.

Basically your view will use roles to get the information out it would like for a particular entry in your model. If you have any database experience, you could consider a role to be similar to a column in a database, where the rows in the database correspond to pieces of data.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top