Search code examples
pythonpyqtpyqt5qtablewidget

Set selection background of disabled checkbox in pyqt5


I have a checkbox that is disabled (the user should not be able to toggle it) but I'm having trouble changing it's background when selected. I'm sure it has to do with the fact that box is disabled, but I'm not sure how to fix it. If there's an easy fix with stylesheets that would be ideal.

I tried messing around with slots/signals but that caused weird issues and I'd rather not fix this issue that way

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import (QApplication,
          QTableView, QAbstractItemView)



class Ui_MainWindow(object):
   def setupUi(self, MainWindow):
       MainWindow.setObjectName("MainWindow")
       MainWindow.resize(400, 300)
       self.centralwidget = QtWidgets.QWidget(MainWindow)
       self.centralwidget.setObjectName("centralwidget")
       MainWindow.setCentralWidget(self.centralwidget)

       self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
       self.tableWidget.setGeometry(QtCore.QRect(50, 40, 310, 50))
       self.tableWidget.setSelectionBehavior(QAbstractItemView.SelectRows)
       self.tableWidget.setSelectionMode(QAbstractItemView. 
          SingleSelection)
       self.tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
       self.tableWidget.verticalHeader().setVisible(False)
       self.tableWidget.horizontalHeader().setVisible(False)
       self.tableWidget.setShowGrid(False)
       self.tableWidget.setStyleSheet("background-color: white; selection-background-color: #353535;")

       self.tableWidget.insertRow(0)

       self.tableWidget.insertColumn(0)
       self.tableWidget.insertColumn(1)
       self.tableWidget.insertColumn(2)


       self.tableWidget.checkBox = QtWidgets.QCheckBox(self.tableWidget)

       self.tableWidget.checkBox.setAttribute(QtCore.Qt.WA_TransparentForMouseEvents)
       self.tableWidget.checkBox.setFocusPolicy(QtCore.Qt.NoFocus)
       self.tableWidget.checkBox.setMaximumSize(30, 30)
       self.tableWidget.checkBox.setStyleSheet("background-color: white; selection-background-color: #353535; padding-left: 10px")
       self.tableWidget.checkBox.setChecked(True)


       self.tableWidget.setCellWidget(0, 1, self.tableWidget.checkBox)




if __name__ == "__main__":
   import sys
   app = QtWidgets.QApplication(sys.argv)
   MainWindow = QtWidgets.QMainWindow()
   ui = Ui_MainWindow()
   ui.setupUi(MainWindow)
   MainWindow.show()
   sys.exit(app.exec_())

Solution

  • The problem in your case is that the QCheckBox to be selected must have the focus, but you have disabled it, and according to what you argue in your comments make me think that you have an XY problem: Your bottom problem is to have the selection per row and enable the checkbox status change depending on the data that the QTableWidget has.

    Considering the above, it is not necessary to use a QCheckBox, just vast to enable the flag Qt::ItemIsUserCheckable, and use a delegate to enable or disable the change of state of the checkbox.

    Considering the above, the solution is:

    import random
    from enum import Flag
    from PyQt5 import QtCore, QtGui, QtWidgets
    
    
    PermissionsRole = QtCore.Qt.UserRole + 1000
    
    
    class Permissions(Flag):
        User = 0
        Admin = 1 << 0
    
    
    class CheckBoxDelegate(QtWidgets.QStyledItemDelegate):
        def editorEvent(self, event, model, option, index):
            if index.data(PermissionsRole) & Permissions.Admin:
                super(CheckBoxDelegate, self).editorEvent(
                    event, model, option, index
                )
            return False
    
    
    class MainWindow(QtWidgets.QMainWindow):
        def __init__(self, parent=None):
            super(MainWindow, self).__init__(parent)
    
            self.m_tablewidget = QtWidgets.QTableWidget(
                selectionBehavior=QtWidgets.QAbstractItemView.SelectRows,
                selectionMode=QtWidgets.QAbstractItemView.SingleSelection,
                editTriggers=QtWidgets.QAbstractItemView.NoEditTriggers,
                showGrid=False,
                columnCount=3,
            )
            delegate = CheckBoxDelegate(self.m_tablewidget)
            self.m_tablewidget.setItemDelegateForColumn(1, delegate)
            self.m_tablewidget.setStyleSheet(
                """
                QTableView
                {
                    background-color: white; 
                    selection-background-color: #353535;
                }
                """
            )
            for header in (
                self.m_tablewidget.horizontalHeader(),
                self.m_tablewidget.verticalHeader(),
            ):
                header.hide()
                if header.orientation() == QtCore.Qt.Horizontal:
                    header.setSectionResizeMode(QtWidgets.QHeaderView.Stretch)
    
            for i in range(10):
                isAdmin = random.choice([Permissions.User, Permissions.Admin])
                self.m_tablewidget.insertRow(self.m_tablewidget.rowCount())
                self.m_tablewidget.setItem(
                    i,
                    0,
                    QtWidgets.QTableWidgetItem(
                        "Is Admin?: {}".format(isAdmin == Permissions.Admin)
                    ),
                )
    
                it = QtWidgets.QTableWidgetItem()
                it.setData(PermissionsRole, isAdmin)
                it.setFlags(it.flags() | QtCore.Qt.ItemIsUserCheckable)
                it.setCheckState(QtCore.Qt.Checked)
                self.m_tablewidget.setItem(i, 1, it)
    
            self.setCentralWidget(self.m_tablewidget)
    
    
    if __name__ == "__main__":
        import sys
    
        app = QtWidgets.QApplication(sys.argv)
        w = MainWindow()
        w.resize(640, 480)
        w.show()
        sys.exit(app.exec_())