PyQt5 非常简单的按钮输入对话框

PyQt5 very simple button input dialog

我想我会尝试 pyqt(5) 进行更改,并希望在脚本启动时创建一个简单的对话框,让用户从三个选项中选择一个。

我的目标是像这样的弹出窗口(在脚本启动时),它将在按下其中一个按钮时关闭,并且 returns 按下按钮的值:

这就是我尝试实现它的方式:

from PyQt5.QtWidgets import QApplication, QDialog, QPushButton, QDialogButtonBox

input_db_connection="None"

class MyDialog(QDialog):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("Choose Database connection")
        self.buttonBox=QDialogButtonBox(self)
    
        for option in ["Production Read", "Production Read&Write", "Development"]:
            b = QPushButton(option)
            b.clicked.connect(lambda x: return_and_close(option))
            self.buttonBox.addButton(b,0)
            del b
    
        def return_and_close(value):
            global input_db_connection
            print(value)
            input_db_connection=value
            self.close()

app = QApplication([])   
dg = MyDialog()
dg.show()
app.exec()

print(input_db_connection)
  1. 我使用了一个全局变量,因为我没有找到从 QApplication return 任何东西的方法。

  2. 无论我按哪个按钮,输出的都是“Development”,输入的最后一个选项?

主要问题在 lambda scope 中:lambda: 中的内容只有在执行时才会被评估。
单击按钮时,for 循环已经完成,此时 option 将是循环中分配的最后一个值。

解决方案是“强制”关键字参数,以便在内部范围内有一个持久引用。请注意,Qt 按钮的 clicked 信号有一个 checked 参数,您 必须 在 lambda 位置参数中考虑它。

那么,与其创建全局变量(这几乎总是一个糟糕的选择),不如正确使用 QDialog 的功能:

  1. 使用 exec(),它阻止执行(但不是事件循环)直到对话框 returns;
  2. 使用 done() 为对话框设置有效结果并通过返回该结果关闭它;
from PyQt5.QtWidgets import *

class MyDialog(QDialog):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("Choose Database connection")
        layout = QVBoxLayout(self)
        self.buttonBox = QDialogButtonBox(self)
        layout.addWidget(self.buttonBox)

        states = [
            (0, "Production Read"), 
            (1, "Production Read&Write"), 
            (2, "Development"), 
        ]

        for value, option in states:
            b = QPushButton(option)
            b.clicked.connect(lambda _, value=value: self.done(value))
            self.buttonBox.addButton(b, 0)


app = QApplication([])   
dg = MyDialog()
print(dg.exec())

补充说明:

  • 总是使用layout managers,创建子widgets是不够的,尝试手动设置几何体还是不行,除非你对Qt事件有很深的了解和深刻的体验、尺寸提示和政策;
  • 不要不必要地调用 del(在这种情况下它也完全没有意义,因为它只会删除 python 引用,并且它是一个局部变量,会在每个 for 循环和__init__ returns 时收集的垃圾,没用);
  • 尽可能避免使用局部函数,而总是更喜欢实例方法;