PyQt - 即使禁用也可以使QAction可选

8
我想要一个具有略微改变行为的QAction。我希望只有在QAction被选中时才会发出信号,并且,即使QAction已被禁用,其复选框仍然可以被选中。例如,如果将QAction设置为setEnabled(False),则无法单击QAction或选中/取消选中它。我喜欢它不能再被点击,但不喜欢我无法切换QAction内部的复选框。是否可能修改它以获得我想要的结果?
我附上了一个示例文件。目标是创建一些解决方案,其中QAction被设置为禁用(setEnabled(False)),但用户仍然可以选中/取消选中它。
#!/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()

1
我可以知道这有什么好处吗?也许我们可以为您的问题找到不同的解决方案,因为这似乎不是“QActions”的预期行为。 - Matho
你能否更好地解释一下,你的问题很令人困惑。 - eyllanesc
setEnabled(False)的目的是禁用QAction上所有类型的事件。 - eyllanesc
不一定非得这样做。老实说,我不在乎使用什么方法,只要它对其他程序员来说是惯用的,并且能让用户视觉上知道“这是不可点击的”。听起来你有更好的想法 - 你会怎么做呢? - ColinKennedy
您希望即使禁用了该“QAction”,也可以使用其中的“checkbox”吗? - eyllanesc
显示剩余10条评论
1个回答

2

既然您想要仍然能够点击QAction来检查和取消选中,我认为没有必要禁用QAction。相反,您可以只是改变它的外观。

您尝试过调整样式表吗?

只需在您的代码中添加这一简单行:

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

我想说的是,你可以根据自己的意愿更改qaction的样式。

你还可以尝试更加复杂和具体的操作,上面的代码将会把菜单中的所有文本变为灰色,你可以指定要更改字体颜色的对象类型,还有更多其他的操作,例如:

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

您可以尝试其他方法来实现您想要的,有时我们会陷入某个问题,但是有其他方式可以达到相同的效果。请快速查看我修改的这段代码,它可以实现类似于您所需的功能。我认为 ")

'''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()

我给你的第一个样式表示例存在缺陷,因为QAction不是一个窗口小部件,所以我无法真正更改它的样式表(它没有样式表),所以我不得不更改菜单的样式表,这会影响其他人。这个第二个示例使用QCheckBox作为窗口小部件,所以我可以专门更改它的样式表,并且我对每个菜单项都有更好的控制:D


在QSS中有没有一种方法可以禁用小部件的点击功能?也许您只是想做一个简单的示例,但颜色更改是不够的,因为即使更改了颜色,QAction上的按钮仍然可以被点击。 - ColinKennedy
我刚刚编辑了我的示例,使用另一种东西代替QAction,这个你可以随时启用和禁用。我认为当需要时,你应该有一些东西来管理你的项目并启用或禁用它。 - yurisnm
告诉我你想要哪种状态。如果它被选中,它能被点击吗?如果它被选中,它是灰色还是黑色的?所有状态情况是什么?你能给我这些情况,这样我就可以更好地理解你所期望的行为了吗? - yurisnm
你发布的修改后的解决方案在使用self.menu.setTearOffEnabled(True)时无法正常工作。实际上,我已经有一个与你发布的类似设置了,但是测试它的用户并不满意,因为他们想要tearoff。基本上,菜单中的禁用操作只有两种状态:选中和未选中。启用的操作仍然只有两种状态:选中和未选中,但是可以通过点击X来执行。唯一的区别是启用的操作可以被点击。我的解决方案使用复选框、按钮和QWidgetAction,与你的解决方案类似,但是tearOff无法正常工作。 - ColinKennedy
对我来说,这绝对是一个bug。在一些论坛上看到有人询问它,并在qt的论坛上报告了一个bug。我正在尝试解决它,但目前还没有取得太大的成功。 - yurisnm
嗯,不确定你之前是否看到我发的链接,但我找到了一个 bug(可能已经被解决,但是这个 bug 存在已有好几年了)https://bugreports.qt.io/browse/QTBUG-1017。如果你那边发现了什么,请告诉我。 - ColinKennedy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接