PyQt5立即显示QMessageBox和QInputDialog

时间:2019-08-19 23:14:51

标签: python python-3.x pyqt pyqt5

我很好奇为什么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都立即显示的功能。

2 个答案:

答案 0 :(得分:1)

问题中引用的方法是QInputDialog和QMessageBox的静态成员,它们是同步的阻塞调用。这是通过模拟而不是调用show,而是在对话框上调用exec来模拟的。 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是一个同步的阻塞调用这一事实,这意味着在处理该对话框之前,不会在应用程序主线程上运行任何其他操作。

答案 1 :(得分:0)

就像@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')