如何允许在PyQt4中调整QMessageBox的大小

5 投票
5 回答
15616 浏览
提问于 2025-04-15 21:42

我正在使用QMessageBox这个很不错的功能,可以选择性地向用户显示详细信息。不过,展开后的窗口还是比较小,大家通常会想要调整窗口大小,以便能看到更多的细节。即使我设置了我认为合适的选项,窗口还是不允许调整大小。

下面是相关的PyQt4代码片段:

mb = QMessageBox()
mb.setText("Results written to '%s'" % filename)
mb.setDetailedText(str(myData))
mb.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
mb.setSizeGripEnabled(True)

我是不是漏掉了什么步骤?或者说这根本就不可能?

5 个回答

2

由于QMessageBox的特性,它不应该允许调整大小。如果你需要可以调整大小的对话框,建议使用QDialog。

说到这里,QMessageBox的固定大小是因为它内部的布局造成的,每当对话框的某些部分(比如按钮、详细文本等)发生变化时,这个布局就会被替换

由于布局管理完全在内部进行,并且它总是会重置对话框的固定大小,所以解决办法是关注相关的事件,特别是LayoutRequest(每当需要重新布局时会被调用)和Resize,并覆盖最大大小。

如果你创建一个子类,解决方案就比较简单:

class ResizableMessageBox(QtWidgets.QMessageBox):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setSizeGripEnabled(True)

    def event(self, event):
        if event.type() in (event.LayoutRequest, event.Resize):
            if event.type() == event.Resize:
                res = super().event(event)
            else:
                res = False
            details = self.findChild(QtWidgets.QTextEdit)
            if details:
                details.setMaximumSize(16777215, 16777215)
            self.setMaximumSize(16777215, 16777215)
            return res
        return super().event(event)

另外,你也可以使用事件过滤器来实现:

class Something(QWidget):
    # ...
    def showMessageBox(self):
        mb = QtWidgets.QMessageBox()
        mb.setSizeGripEnabled(True)
        mb.setWindowTitle('Hello')
        mb.setText('I am a message box')
        mb.setDetailedText('very long text ' * 10)
        mb.setProperty('resizable', True)
        mb.installEventFilter(self)
        mb.exec()

    def eventFilter(self, obj, event):
        if (isinstance(obj, QtWidgets.QMessageBox) 
            and obj.property('resizable')
            and event.type() in (event.LayoutRequest, event.Resize)):
                if event.type() == event.Resize:
                    obj.event(event)
                details = obj.findChild(QtWidgets.QTextEdit)
                if details:
                    details.setMaximumSize(16777215, 16777215)
                obj.setMaximumSize(16777215, 16777215)
                return True
        return super().eventFilter(obj, event)

注意:以上方法都不适用于QMessageBox的静态方法,因为它们会创建一个私有实例。

5

如果你想做一个可以调整大小的消息框,请看看下面的代码是否适合你:

class MyMessageBox(QtGui.QMessageBox):
    def __init__(self):
        QtGui.QMessageBox.__init__(self)
        self.setSizeGripEnabled(True)

    def event(self, e):
        result = QtGui.QMessageBox.event(self, e)

        self.setMinimumHeight(0)
        self.setMaximumHeight(16777215)
        self.setMinimumWidth(0)
        self.setMaximumWidth(16777215)
        self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)

        textEdit = self.findChild(QtGui.QTextEdit)
        if textEdit != None :
            textEdit.setMinimumHeight(0)
            textEdit.setMaximumHeight(16777215)
            textEdit.setMinimumWidth(0)
            textEdit.setMaximumWidth(16777215)
            textEdit.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)

        return result

这是调用消息框的方式:

mb = MyMessageBox()
mb.setText("Results written to '%s'" % 'some_file_name')
mb.setDetailedText('some text')
mb.exec_()

这个解决方案来自于 这里

希望这对你有帮助,祝好

6

这是我会使用的解决方案。虽然这并不会让对话框可以调整大小,但它会在详细信息框可见时,让对话框自动调整到一个合适的大小。我毫不掩饰地借鉴了serge_gubenko的答案中的一些想法。即使你更想实现他的调整大小功能,我还是谦虚地提供了一些其他的改进建议。

# Safe since everything in the namespace begins with 'Q'
from PyQt4.QtGui import *

class MyMessageBox(QMessageBox):

    # This is a much better way to extend __init__
    def __init__(self, *args, **kwargs):            
        super(MyMessageBox, self).__init__(*args, **kwargs)
        # Anything else you want goes below

    # We only need to extend resizeEvent, not every event.
    def resizeEvent(self, event):

        result = super(MyMessageBox, self).resizeEvent(event)

        details_box = self.findChild(QTextEdit)
        # 'is not' is better style than '!=' for None
        if details_box is not None:
            details_box.setFixedSize(details_box.sizeHint())

        return result

撰写回答