【问题标题】:PyQt5 Display QMessageBox and QInputDialog immediatelyPyQt5 立即显示 QMessageBox 和 QInputDialog
【发布时间】:2019-08-19 23:14:51
【问题描述】:

我很好奇是什么让 QInputDialog 和 QMessageBox.question 总是立即显示?对于其他 PyQT 元素,显示 UI 内容需要一个初始序列。

# Example of a Basic PyQT5 UI Application
app = QApplication(sys.argv)

w = QWidget()
w.resize(250, 150)
w.move(300, 300)
w.setWindowTitle('Simple')
w.show()

sys.exit(app.exec_())

我一直在努力寻找合适的文档,但没有看到任何突出的东西。所以我希望有人能指出我应该如何修改小部件类或在哪里可以找到合适的文档。

from PyQt5.QtWidgets import QMainWindow, QApplication, QWidget, QPushButton, QAction, QLineEdit, QLabel, QMessageBox, QHBoxLayout, QInputDialog
from PyQt5.QtCore import pyqtSlot, Qt
from PyQt5.QtGui import QIcon, QPixmap

class QuestionPopup(QWidget):
    def __init__(self, question = None):
        super().__init__()
        self.title = 'Question Popup'
        self.left = 250
        self.top = 50
        self.width = 320
        self.height = 200
        self.question = question
        self._response = None
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        buttonReply = QMessageBox.question(self, 'PyQt5 message', self.question, QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

        if buttonReply == QMessageBox.Yes:
            self.response = True
        else:
            self.response = False

        self.show() 

    def getText(self):
        text, okPressed = QInputDialog.getText(self, "Get text","Your name:", QLineEdit.Normal, "")
        if okPressed and text != '':
            print(text)

我的目标是创建将显示图像并要求用户输入图像的自定义对话框。我的代码非常复杂,我不能简单地显示一个新的 UI 窗口。我需要让 QMessageBox 和 QInputDialog 立即出现的功能。

【问题讨论】:

  • 您能详细解释一下您的意思吗?
  • 当然,我相信我可能有点含糊。我有一个已经通过 python + QML 运行的主 UI。我有这个子模块,除了它是由它产生的之外,它对主 UI 没有真正的引用。这个其他 UI 是用 pyqt 编写的。为了从这部分代码中提示用户,我需要有本质上可以自己生成的 UI 元素。 QInputDialog 和 QMessageBox 似乎可以做到这一点。
  • mmmm,你的解释不清楚,自己解释清楚。但另一方面,QML 和 QtWidgets 中的逻辑是不同的,因此使用 QtWidgets 的解决方案(您似乎想要)在 QML 中不一定有效。 立即显示是什么意思?
  • 很抱歉。我对 Qt 还是比较陌生,这个项目的范围已经扩大了很多。如果您查看我的原始帖子,如果我在我的主 UI 运行时创建我的 QuestionPopup() 类的实例,它将在我期望的时候被调用。如果我创建一个包含此示例中的代码pythonspot.com/pyqt5-textbox-example 的类,则不会出现该窗口。所以我很好奇是什么让 QMessagebox 和其他 QElement 彼此区分开来。再次抱歉,如果不清楚。
  • @Knoose 你所有的解释都很清楚,eyllanesc 就是搞不懂。

标签: python python-3.x pyqt pyqt5


【解决方案1】:

您的问题中引用的方法是 QInputDialog 和 QMessageBox 的静态成员,它们是同步的阻塞调用。这是通过在对话框上调用 exec 而不是调用 show 来模拟的。 exec 类似于 show (在 pyqt 中, exec 是 exec_ 以避免与 python 内置 exec 发生冲突),但它实际上会阻止所有其他 UI 组件,直到它提供控制权(从技术上讲,它通过暂停主事件循环并运行它来做到这一点自己特定于最终放弃控制的对话框)。在此处查看更多信息:https://doc.qt.io/qt-5/qmessagebox.html#exec

请注意,这是特定于这些静态函数的行为。您可以在不使用这些函数的情况下创建自己的 QMessageBox,它会以正常方式运行,即在您明确调用 show 之前不会显示。

这是一个示例函数,它显示了 QMessageBox.static 如何在后台实现的高级细节(尽管这不是实际代码):

    def question(parent, title, message, buttons):
        message_box = QMessageBox(question_icon, title, message, buttons)
        return message_box.exec_()

要点是获取那些静态函数正在使用的行为,您需要在对话框上调用 exec_ 而不是显示。请注意, exec_ 仅适用于特定的小部件类型,尤其是从 QDialog 继承的任何东西。您还应该注意 exec 是一个同步的阻塞调用,这意味着在处理该对话框之前,在您的应用程序的主线程上运行的任何其他操作都不会运行。

【讨论】:

    【解决方案2】:

    正如@TheKewlStore 所说,您引用的方法是静态的,并且您可以修改的内容受到限制。它们包含使它们立即显示的内置属性,而不需要使用 show()app.exec_() 下面解决了您问题的这一部分:“...如何修改小部件类”以显示您的图像并允许用户输入以及显示一个消息框。

    这将首先创建一个简单的消息框,然后在其关闭时,将创建并显示一个基本对话框,该对话框可以显示图像、指示用户的一行文本、用户输入文本的位置、以及一个确定和取消按钮——我只连接了确定按钮来简单地打印用户的输入。显然,您可以为按钮插入任何您想要的命令以及用户输入会发生什么。我还使用了一些网格布局,主要是因为我喜欢它保持东西干净的方式,但它们并不是完成这项工作的必要条件。也可以使盒子的尺寸更加动态,我只是觉得这里不需要它。

    import sys
    from PyQt5.QtWidgets import QApplication, QWidget, QInputDialog, QLineEdit
    from PyQt5.QtGui import QIcon
    from PyQt5 import QtWidgets, QtCore
    import PyQt5
    import os
    
    class MsgBox(object):
        def setupUi(self, show_msgbox):
            show_msgbox.setObjectName("show_msgbox")
            show_msgbox.setText('Show your message text here')
    
    class MsgPrompt(PyQt5.QtWidgets.QMessageBox, MsgBox):
        app = PyQt5.QtWidgets.QApplication(sys.argv)
    
        def __init__(self):
            super(MsgPrompt, self).__init__()
            self.setupUi(self)
            super(MsgPrompt, self).exec_()
    
    class UserInput(object):
        def setupUi(self, get_user_input):
        # Basic shape
        self.width = 425
        get_user_input.setObjectName("get_user_input")
        get_user_input.resize(425, self.width)
        self.frame = QtWidgets.QFrame(get_user_input)
        self.frame.setGeometry(QtCore.QRect(11, 10, 401, 381))
        self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame.setFrameShadow(QtWidgets.QFrame.Sunken)
        self.frame.setObjectName("frame")
        # Creating the grid layout for most of the display elements
        self.gridLayoutWidget = QtWidgets.QWidget(self.frame)
        self.gridLayoutWidget.setGeometry(QtCore.QRect(10, 10, 381, 361))
        self.gridLayoutWidget.setObjectName("gridLayoutWidget")
        self.get_user_input_layout = QtWidgets.QGridLayout(self.gridLayoutWidget)
        self.get_user_input_layout.setContentsMargins(5, 5, 5, 5)
        self.get_user_input_layout.setObjectName("get_user_input_layout")
        # Grid layout for the buttons
        self.buttonLayoutGrid = QtWidgets.QWidget(get_user_input)
        self.buttonLayoutGrid.setGeometry(QtCore.QRect(10, 390, 401, 41))
        self.buttonLayoutGrid.setObjectName("buttonLayoutGrid")
        self.buttonLayout = QtWidgets.QGridLayout(self.buttonLayoutGrid)
        self.buttonLayout.setContentsMargins(0, 0, 0, 0)
        self.buttonLayout.setObjectName("buttonLayout")
        # Adding buttons    
        self.buttonOK = QtWidgets.QPushButton(self.buttonLayoutGrid)
        self.buttonOK.setObjectName("buttonOK")
        self.buttonOK.setText("OK")
        self.buttonLayout.addWidget(self.buttonOK, 0, 1, 1, 1)
        self.buttonCancel = QtWidgets.QPushButton(self.buttonLayoutGrid)
        self.buttonCancel.setObjectName("buttonCancel")
        self.buttonCancel.setText("CANCEL")
        self.buttonLayout.addWidget(self.buttonCancel, 0, 2, 1, 1)
        # Adding the place for the image
        self.image = QtWidgets.QLabel(self.gridLayoutWidget)
        self.get_user_input_layout.addWidget(self.image, 0, 0, 1, 1)
        # Add instructions for the user
        self.user_prompt_text = QtWidgets.QLabel(self.gridLayoutWidget)
        self.user_prompt_text.setText('WHAT IS THIS PIC?')
        self.user_prompt_text.setAlignment(PyQt5.QtCore.Qt.AlignLeft)
        self.get_user_input_layout.addWidget(self.user_prompt_text, 1, 0, 1, 1)
        # Add a field for the user to enter text    
        self.user_input_box = PyQt5.QtWidgets.QLineEdit(self.gridLayoutWidget)
        self.user_input_box.setObjectName('user_input_box')
        self.user_input_box.setEnabled(True)
        self.get_user_input_layout.addWidget(self.user_input_box, 2, 0, 1, 1)
        # This is an optional call
        QtCore.QMetaObject.connectSlotsByName(get_user_input)
    
    class UserInputPrompt(PyQt5.QtWidgets.QDialog, UserInput):
        app = PyQt5.QtWidgets.QApplication(sys.argv)
    
        def __init__(self, path_to_image):
            super(UserInputPrompt, self).__init__()
            self.setupUi(self)
            self.path_to_image = path_to_image
            self.user_input_box.setFocus()
            self.buttonOK.clicked.connect(self.get_user_input)
            self.image.setPixmap(PyQt5.QtGui.QPixmap(self.path_to_image).scaledToWidth(self.width
            self.image.show()
            super(UserInputPrompt, self).exec_()        
    
        def get_user_input(self):
            print(self.user_input_box.text())
    
    MsgPrompt()
    UserInputPrompt('your_image_file.jpg')
    

    【讨论】:

      猜你喜欢
      • 2015-07-08
      • 2023-01-30
      • 2020-01-04
      • 1970-01-01
      • 2012-07-18
      • 1970-01-01
      • 1970-01-01
      • 2016-10-21
      • 1970-01-01
      相关资源
      最近更新 更多