Search code examples
pythonqtpyqtqtablewidgetitem

disabled qtablewidgetitem is not shown gray


i have a qtablewidgetitem and inside it there is a QCheckbox

when disabling qtablewigetitem as follow

    flags = self.item(row+1, self.columns["USER_ACCESS"]).flags()
    flags |= QtCore.Qt.ItemIsSelectable
    flags |= QtCore.Qt.ItemIsEditable
    flags |= QtCore.Qt.ItemIsEnabled
    self.item(row+1, self.columns["USER_ACCESS"]).setFlags(flags)

it is disabled and i can't click on it but it is dispalyed as it stills enabled.

i want to display it colored in gray

UPDATE:

class CheckBoxDelegate(QtGui.QStyledItemDelegate):
    """
    A delegate that places a fully functioning QCheckBox in every
    cell of the column to which it's applied
    """
    def __init__(self, parent):
        QtGui.QStyledItemDelegate.__init__(self, parent)
        self.parent = parent

    def createEditor(self, parent, option, index):
        '''
        Important, otherwise an editor is created if the user clicks in this cell.
        ** Need to hook up a signal to the model
        '''
        return None

    def paint(self, painter, option, index):
        '''
        Paint a checkbox without the label.
        '''

        checked = index.data() #.toBool()
        check_box_style_option = QtGui.QStyleOptionButton()

        if (index.flags() & QtCore.Qt.ItemIsEditable) > 0:
            check_box_style_option.state |= QtGui.QStyle.State_Enabled
        else:
            check_box_style_option.state |= QtGui.QStyle.State_ReadOnly

        if checked:
            check_box_style_option.state |= QtGui.QStyle.State_On
        else:
            check_box_style_option.state |= QtGui.QStyle.State_Off

        check_box_style_option.rect = self.getCheckBoxRect(option)

        #if not index.model().hasFlag(index, Qt.ItemIsEditable):
        check_box_style_option.state |= QtGui.QStyle.State_ReadOnly

        check_box_style_option.state |= QtGui.QStyle.State_Enabled

        QtGui.QApplication.style().drawControl(QtGui.QStyle.CE_CheckBox, check_box_style_option, painter)

    def editorEvent(self, event, model, option, index):
        '''
        Change the data in the model and the state of the checkbox
        if the user presses the left mousebutton or presses
        Key_Space or Key_Select and this cell is editable. Otherwise do nothing.
        '''
        if not (index.flags() & QtCore.Qt.ItemIsEditable) > 0:
            return False

        # Do not change the checkbox-state
        if event.type() == QtCore.QEvent.MouseButtonPress:
          return False
        if event.type() == QtCore.QEvent.MouseButtonRelease or event.type() == QtCore.QEvent.MouseButtonDblClick:
            if event.button() != QtCore.Qt.LeftButton or not self.getCheckBoxRect(option).contains(event.pos()):
                return False
            if event.type() == QtCore.QEvent.MouseButtonDblClick:
                return True
        elif event.type() == QtCore.QEvent.KeyPress:
            if event.key() != QtCore.Qt.Key_Space and event.key() != QtCore.Qt.Key_Select:
                return False
            else:
                return False

        # Change the checkbox-state
        self.setModelData(None, model, index)
        return True

    def setModelData (self, editor, model, index):
        '''
        The user wanted to change the old state in the opposite.
        '''
        newValue = QtCore.Qt.Checked if not index.data() else QtCore.Qt.Unchecked
        model.setData(index, newValue, QtCore.Qt.EditRole)
        self.parent.sort()
        self.parent.sort()

    def getCheckBoxRect(self, option):
        check_box_style_option = QtGui.QStyleOptionButton()
        check_box_rect = QtGui.QApplication.style().subElementRect(QtGui.QStyle.SE_CheckBoxIndicator, check_box_style_option, None)
        check_box_point = QtCore.QPoint (option.rect.x() +
                            option.rect.width() / 2 -
                            check_box_rect.width() / 2,
                            option.rect.y() +
                            option.rect.height() / 2 -
                            check_box_rect.height() / 2)
        return QtCore.QRect(check_box_point, check_box_rect.size())

and here is how i put it inside the QTableWidgetItem

def delegate(self, column, delegater):
    self.setItemDelegateForColumn(column, delegater)
    pass

Solution

  • Use ^ instead.

    flags ^= QtCore.Qt.ItemIsEnabled
    

    | is the bitwise-OR. What it does is turns the enabled flag ON regardless of its original state. ^ will toggle it.

    If you want to TURN OFF the flag REGARDLESS of its original state, just AND (&) it with its COMPLIMENT (~) like so:

    flags = flags & ~QtCore.Qt.ItemIsEnabled
    

    You can apply these principles of any flags that you want to turn off or on, like QtCore.Qt.ItemIsSelectable etc.

    In your case, the code would be something like:

    flags = self.item(row+1, self.columns["USER_ACCESS"]).flags()
    flags &= ~QtCore.Qt.ItemIsSelectable
    flags &= ~QtCore.Qt.ItemIsEditable
    flags &= ~QtCore.Qt.ItemIsEnabled
    self.item(row+1, self.columns["USER_ACCESS"]).setFlags(flags)
    

    Check out this for more details: https://wiki.python.org/moin/BitwiseOperators

    Another wonderful answer that touches on this topic (very useful): How to find specific Qt.ItemFlag occurrence into custom Qt.ItemFlags instance in PyQt?

    UPDATE-1: If your cells have items in the form of Widgets (egs. QCheckBox), you might want to approach it differently. You might want to disable the corresponding widget instead. So in your case you would do something like:

    my_checkbox_item = self.cellWidget(row+1, self.columns["USER_ACCESS"])
    my_checkbox_item.setEnabled(False)
    

    UPDATE-2: Since, you have now updated your question with more code, here's another update: In your paint method you have to apply the same bitwise operation principles as illustrated in the first part of this answer. So you would have to do something like:

        if (index.flags() & QtCore.Qt.ItemIsEditable) > 0:
            check_box_style_option.state |= QtGui.QStyle.State_Enabled
            check_box_style_option.state &= ~QtGui.QStyle.State_ReadOnly
        else:
            check_box_style_option.state &= ~QtGui.QStyle.State_Enabled
            check_box_style_option.state |= QtGui.QStyle.State_ReadOnly
    

    .. and REMOVE these lines:

        #if not index.model().hasFlag(index, Qt.ItemIsEditable):
        check_box_style_option.state |= QtGui.QStyle.State_ReadOnly
    
        check_box_style_option.state |= QtGui.QStyle.State_Enabled
    

    That should fix it.