0

We are making a Python GUI program which displays a table of items and the table has several columns. In our implementation, we created several sub-classes which inherit from QtWidgets.QTableWidgetItem for different kinds of cells, for example, we have EnumCell and BuySellCell. Now I want to have a cell which draws a progress bar. I take this link as a reference to do that. And my code looks like this:

class ProgressDelegate(QtWidgets.QStyledItemDelegate):
  def paint(self, painter, option, index):
    progress = index.data(QtCore.Qt.UserRole+1000)
    opt = QtWidgets.QStyleOptionProgressBar()
    opt.rect = option.rect
    opt.minimum = 0
    opt.maximum = 100
    opt.progress = progress
    opt.text = "{}%".format(progress)
    opt.textVisible = True
    QtWidgets.QApplication.style().drawControl(QtWidgets.QStyle.CE_ProgressBar, opt, painter)

class ProgressBarCell(BaseCell):    

  def __init__(self, content: str, parent : QtWidgets.QTableWidget = None):
    """"""
    super(ProgressBarCell, self).__init__(content, parent)        
    self.delegate = ProgressDelegate(parent)                
    self.parent = parent

  def set_content(self, content: Any) -> None:        
    if content or content == 0:            
        self.setData(QtCore.Qt.UserRole+1000, content)

    # Since we need a column index to set the delegate for the column, we have to have a separate function to do that 
    # (we can't do it in the constructor because we need all sub-classes of BaseCell have the same constructor signatures)
  def assign_column_number(self, column : int):
    self.parent.setItemDelegateForColumn(column, self.delegate)

And now in order to use this, I first need to create a QTableWidget and a ProgressBarCell, pass the former to the latter, determine the column position of the ProgressBarCell and call the function assign_column_number

It works fine and the progress bar is displayed as expected. It's just not easy to use because of two things: 1) we have to assign a column index (hence the function assign_column_number) for the parent (QtWidgets.QTableWidget) and 2) we have to make the ProgressDelegate and assign it to the parent (and the column index is used here).

I imagine there might be some way to make a self-drawing cell for the progress bar. I.e., I don't want to call the function assign_column_number (it doesn't matter if we have to pass the parent). After all, the cell itself already has enough information to draw the progress bar.

Does anyon happen to have similar experience? Thank you very much!

tete
  • 4,859
  • 11
  • 50
  • 81
  • Items are just for storing data. It's not their responsibility to paint themselves. After all, the model they are part of could be shared between different views each with their own visual representation. For that same reason you really shouldn't set the item delegate of the table widget from within the item. – Heike Apr 08 '21 at 08:42
  • @Heike On some level I see your point. But aren't cells/table all part of the presentation layer whose job is to display the data? And I really don't want to set the delegate of the table widget from within t he item, I want the cell to draw itself, if it fits its job description – tete Apr 08 '21 at 09:23
  • No, they are not. While QTableWidget is a higher level of the representation, it's still part of the Model-View pattern. The items you're subclassing are part of the model, the delegate is part of the view. The fact that QTableWidget incorporates a model is ininfluential, it's just a convenience implementation that allows using the MV pattern avoiding the need to create a model. Q[\*]WidgetItems are abstract representations of *data*, they provide hints about how they *could be shown* (background/foreground color, font), but they are not, nor should be, responsible of actually *display* data. – musicamante Apr 08 '21 at 12:54

0 Answers0