Python PyQt5 将不再显示此消息复选框添加到 QMessageBox

2022-01-12 00:00:00 python pyqt5

问题描述

我正在努力让它发挥作用.我试图从 c++ 帖子转置为 python,但没有任何乐趣:QMessageBox 带有不再显示此内容"复选框

I am struggling to get this working. I tried to transpose from a c++ post into python with no joy: QMessageBox with a "Do not show this again" checkbox

我的粗略代码如下:

from PyQt5 import QtWidgets as qtw

...
mb = qtw.QMessageBox
cb = qtw.QCheckBox

# following 3 lines to get over runtime errors
# trying to pass the types it was asking for
# and surely messing up
mb.setCheckBox(mb(), cb())
cb.setText(cb(), "Don't show this message again")
cb.show(cb())
ret = mb.question(self,
                 'Close application',
                 'Do you really want to quit?',
                 mb.Yes | mb.No )
if ret == mb.No:
   return
self.close()

上面的执行没有错误,但复选框没有显示(消息框显示).考虑到我在基因上很愚蠢......而且很慢,非常慢.所以请在我的学习曲线上放轻松

the above executes with no errors but the checkbox ain't showing (the message box does). consider that I am genetically stupid... and slow, very slow. so please go easy on my learning curve


解决方案

尝试移植"时代码,重要的是要了解源语言的基础,对目标有更深入的了解.

When trying to "port" code, it's important to know the basis of the source language and have a deeper knowledge of the target.

例如,获取代码的第一行和引用的问题:

For instance, taking the first lines of your code and the referenced question:

QCheckBox *cb = new QCheckBox("Okay I understand");

上面的 C++ 行表示正在创建一个 QCheckBox 类型的新对象 (cb),并为其分配了 QCheckBox(...) 的结果,该结果返回该类的实例.为了阐明对象是如何声明的,下面是一个简单的整数变量的创建方式:

The line above in C++ means that a new object (cb) of type QCheckBox is being created, and it's assigned the result of QCheckBox(...), which returns an instance of that class. To clarify how objects are declared, here's how a simple integer variable is created:

int mynumber = 10

这是因为 C++ 和许多语言一样,需要对象 type 来声明.

This is because C++, like many languages, requires the object type for its declaration.

在 Python 中,这是一种动态类型语言,这不是必需的(但自 Python 3.6 起是可能的),但您仍然需要创建实例,这是通过使用类上的括号来实现的(这会导致 调用 它并导致调用 __new__ 然后调用 __init__).那么你的代码的前两行应该是:

In Python, which is a dynamic typing language, this is not required (but it is possible since Python 3.6), but you still need to create the instance, and this is achieved by using the parentheses on the class (which results in calling it and causes both calling __new__ and then __init__). The first two lines of your code then should be:

mb = qtw.QMessageBox()
cb = qtw.QCheckBox()

然后,问题是您每次都使用上述类的新实例调用其他方法.

Then, the problem is that you're calling the other methods with new instances of the above classes everytime.

实例方法(如setCheckBox)以实例作为第一个参数隐式调用,通常称为self.

An instance method (such as setCheckBox) is implicitly called with the instance as first argument, commonly known as self.

checkboxInstance = QCheckBox()
checkboxInstance.setText('My checkbox')
# is actually the result of:
QCheckBox.setText(checkboxInstance, 'My checkbox')

最后一行或多或少意味着:调用类 QCheckBox 的 setText 函数,使用实例和文本作为其参数.事实上,如果 QCheckBox 是一个真正的 Python 类,setText() 应该是这样的:

The last line means, more or less: call the setText function of the class QCheckBox, using the instance and the text as its arguments. In fact, if QCheckBox was an actual python class, setText() would look like this:

class QCheckBox:
    def setText(self, text):
        self.text = text

当您执行 cb = qtw.QCheckBox 时,您只创建了对类的 another 引用,而每次执行 cb() 时,您都会创建一个新的实例;mb 也是如此,因为您创建了对消息框类的另一个引用.

When you did cb = qtw.QCheckBox you only created another reference to the class, and everytime you do cb() you create a new instance; the same happens for mb, since you created another reference to the message box class.

下面一行:

mb.setCheckBox(mb(), cb())

等同于:

QMessageBox.setCheckBox(QMessageBox(), QCheckBox())

由于您每次都在创建新实例,因此结果绝对没有:没有对新实例的引用,并且在处理该行后它们将立即被丢弃(垃圾收集",也就是删除).

Since you're creating new instances every time, the result is absolutely nothing: there's no reference to the new instances, and they will get immediately discarded ("garbage collected", aka, deleted) after that line is processed.

实际上应该这样做:

mb = qtw.QMessageBox()
cb = qtw.QCheckBox()

mb.setCheckBox(cb)
cb.setText("Don't show this message again")

现在,您的代码中有一个根本缺陷:question() 是一个 static 方法(实际上,对于 Python,它更像是一个类方法).静态方法和类方法是不作用于实例的函数,而只作用于/作用于类.QMessageBox 的静态方法,如 questionwarning 使用提供的参数创建 QMessageBox 的 new instance,因此您之前在实例上所做的一切您创建的内容将被完全忽略.

Now, there's a fundamental flaw in your code: question() is a static method (actually, for Python, it's more of a class method). Static and class methods are functions that don't act on an instance, but only on/for a class. Static methods of QMessageBox like question or warning create a new instance of QMessageBox using the provided arguments, so everything you've done before on the instance you created is completely ignored.

这些方法是方便的函数,它们允许简单地创建消息框而无需编写太多代码.由于这些方法只允许基于它们的参数进行定制(不包括添加复选框),因此您显然不能使用它们,并且您必须对它们在后台"执行的操作进行编码.明确的.

These methods are convenience functions that allow simple creation of message boxes without the need to write too much code. Since those methods only allow customization based on their arguments (which don't include adding a check box), you obviously cannot use them, and you must code what they do "under the hood" explicitly.

这是最终代码的外观:

    # create the dialog with a parent, which will make it *modal*
    mb = qtw.QMessageBox(self)
    mb.setWindowTitle('Close application') 
    mb.setText('Do you really want to quit?') 
    # you can set the text on a checkbox directly from its constructor
    cb = qtw.QCheckBox("Don't show this message again")
    mb.setCheckBox(cb)
    mb.setStandardButtons(mb.Yes | mb.No)
    ret = mb.exec_()
    # call some function that stores the checkbox state
    self.storeCloseWarning(cb.isChecked())
    if ret == mb.No:
        return
    self.close()

相关文章