Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PyQt - Make QAction checkable even if it is disabled

Tags:

python

pyqt

I want a QAction that has a slightly altered behavior. I want the QAction to only emit a signal whenever it is checked and also, I want its checkbox to always be checkable, even if the QAction is has been disabled. For example, if you set a QAction to setEnabled(False), you can't click the QAction or check/uncheck it. I like that it can't be clicked anymore but dislike that I can't toggle the checkbox inside the QAction. Is it possible to modify it to get what I'm looking for?

I attached an example file, below. The goal is to make some solution where QAction is set to disabled (setEnabled(False)) but the user can still check/uncheck it.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

'''An example file with a QAction that stays checkable.'''

# IMPORT STANDARD LIBRARIES
import sys

# IMPORT THIRD-PARTY LIBRARIES
from Qt import QtWidgets
from Qt import QtCore


class AlwaysOpenAction(QtWidgets.QAction):
    def __init__(self, *args, **kwargs):
        super(AlwaysOpenAction, self).__init__(*args, **kwargs)
        self.toggled.connect(self.printout)

    def printout(self):
        if self.isChecked():
            print('Checkbox was checked')


class WindowTest(QtWidgets.QWidget):

    '''A basic window.'''

    def __init__(self, parent=None):
        '''Init the window.'''
        super(WindowTest, self).__init__(parent=parent)
        self.setLayout(QtWidgets.QHBoxLayout())
        self.menubar = QtWidgets.QMenuBar(parent=self)
        self.menu = self.menubar.addMenu('Some menu')

        action = AlwaysOpenAction('something', self.menu)
        action.setCheckable(True)
        action.setEnabled(False)

        self.menu.addAction(action)
        self.layout().addWidget(self.menubar)
        self.resize(500, 400)


def main():
    '''Do the window test.'''
    qapp = QtWidgets.QApplication(sys.argv)
    window = WindowTest()
    window.show()
    sys.exit(qapp.exec_())


if __name__ == '__main__':
    main()
like image 226
ColinKennedy Avatar asked Apr 24 '17 19:04

ColinKennedy


1 Answers

since you want to be able to still click in the QAction to check and uncheck I don't think it would be necessary to disable the QAction. Instead you could just change the appearance of it. Have you tried mess around with Stylesheet?

Just try to add this simple line in your code:

self.menu.setStyleSheet("""color: gray;""")

So what I'm trying to say here is that you can change the style of your qaction according to your will.

You can also try something more elaborated and more specific, the above line will change every text inside your menu to gray, you can specify what kind of object you want to change the font color, and much more, for example:

self.menu.setStyleSheet("""QPushButton{background-color: red}""")

and so on...

You could try some other approaches to achieve what you want, sometimes we just get stuck in something and there are other ways to do the same. Have a fast look in this piece of code I modified that makes something similar to what you want, I think ")

'''An example file with a QAction that stays checkable.'''

# IMPORT STANDARD LIBRARIES
import sys

# IMPORT THIRD-PARTY LIBRARIES
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QCheckBox
from PyQt5.QtWidgets import QHBoxLayout
from PyQt5.QtWidgets import QMenuBar
from PyQt5.QtWidgets import QWidget
from PyQt5.QtWidgets import QWidgetAction



class CheckBox(QCheckBox):

    def __init__(self, name):
        super(CheckBox, self).__init__()
        self.update_color()
        self.setText(name)

    def mousePressEvent(self, event):
        self.update_color()
        super(CheckBox, self).mousePressEvent(event)

    def update_color(self):
        if self.isChecked():
            self.setStyleSheet("color: gray;")
        else:
            self.setStyleSheet("")

class WindowTest(QWidget):

    '''A basic window.'''

    def __init__(self, parent=None):
        '''Init the window.'''
        super(WindowTest, self).__init__(parent=parent)
        self.setLayout(QHBoxLayout())
        self.menubar = QMenuBar(parent=self)
        self.menu = self.menubar.addMenu('Some menu')
        self.menu.setContentsMargins(10,10,10,10)
        self.widget_action = QWidgetAction(self)
        self.button = CheckBox("some")
        self.button.setCheckable(True)
        self.button.setFixedSize(100, 20)
        self.widget_action.setDefaultWidget(self.button)
        self.menu.addAction(self.widget_action)
        self.setFixedSize(500,200)


def main():
    '''Do the window test.'''
    qapp = QApplication(sys.argv)
    window = WindowTest()
    window.show()
    sys.exit(qapp.exec_())


if __name__ == '__main__':
    main()

Since the first example of stylesheet I gave u has a flaw because QAction is not a Widget so I cant really change its stylesheet(it doesn't have one) so I had to change the menu stylesheet what would affect everyone else. This second example uses QCheckBox which is a widget so I can specifically change its stylesheet and I have a better control above each one item from menu :D

like image 58
yurisnm Avatar answered Nov 12 '22 02:11

yurisnm