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

Posted

技术标签:

【中文标题】如何允许在 PyQt4 中调整 QMessageBox 的大小【英文标题】:How to allow resizing of QMessageBox in PyQt4 【发布时间】:2010-04-16 18:38:19 【问题描述】:

我正在使用 QMessageBox 中的好功能来选择性地向用户显示详细的文本。然而,扩展后的窗口仍然很小,人们会立即尝试调整窗口大小,以便看到更多细节。即使设置了我认为正确的设置,它也不允许调整大小。

这里是PyQt4的相关sn-p代码:

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

我是否错过了一个步骤和/或这是否可能?

【问题讨论】:

你的意思是QMessageBox在显示的时候还不够大,不能显示你的内容(比如东西被截断了)? 对不起,我不清楚。我的意思是详细的文本仅限于 small 文本区域(带有滚动条)。可见,但从用户的角度来看并不令人愉快。如果 QMessageBox 可以根据用户的需要手动调整大小,它将大大改善整体体验。即使调用了setSizePolicy()setSizeGripEnabled(),仍然无法调整窗口大小。 您尝试过最小扩展尺寸策略吗?除此之外,检查一下maximumSize 的设置。您可能需要继承 QMessageBox 并重新实现 sizeHint() 以返回您想要的内容。我一直发现有一些巫术涉及让***小部件根据其内容适当地重新调整自己的大小。您可以尝试的另一件事是设置布局的大小约束:mb.layout()->setSizeConstraint(QLayout::SetMaximumSize)(啊,那是 c++ - 不熟悉 python 语法) 【参考方案1】:

如果您想制作一个可调整大小的消息框,请检查以下代码是否适合您:

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_()

解决方案取自here

希望这会有所帮助,问候

【讨论】:

这绝对是在正确的轨道上(可惜它必须在事件处理程序中完成)。对话框现在确实会调整大小,但所有调整大小都会转到顶部的标签,而不是文本框。我花了大约半个小时来设置其他组件的sizePolicy 和底层布局的rowStretch,但没有进一步了解。这绝对比我拥有的要好。如果我弄清楚如何为文本区域提供所有额外的垂直空间,我会发布后续内容。 @serge_gubenko 当我按下对话框上的最大化按钮(按下“显示详细信息”按钮时显示),对话框立即最大化,然后立即恢复正常(并移动到屏幕的左上角)。知道如何修复最大化按钮的工作吗? 这似乎是迄今为止最好的解决方案。但是,每次单击“显示详细信息”/“隐藏详细信息”按钮时,它都会调整为原始的小尺寸。似乎QMessageBox 内部有一个updateSize() 方法正在计算大小,但覆盖它并没有任何区别,至少在 PyQt 中是这样。 我尝试在使用手柄拖动和调整大小时打印出所有事件类型。通过评论一些事件可以正常工作,最后我只剩下一个:QEvent::CursorChange 来处理。【参考方案2】:

这是我会使用的解决方案。这不会使对话框可调整大小,但会在详细信息框可见时使对话框自身更改为合理的大小。我毫不掩饰地从 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

【讨论】:

这在 linux 上根本不起作用。但即使它确实有效,它也不会回答这个问题,因为它不会使消息框可调整大小。 (PS:在这个例子中覆盖__init__是完全多余的)。【参考方案3】:

这可行,但仅在 Gnome 2 下的 Linux 上进行了测试。它只在水平方向调整大小,除非打开“显示详细信息”文本,在这种情况下,它会在两个方向上调整大小。 “显示详细信息”按钮仍会将其重置为初始大小,这取决于您的 pov,这是一个功能还是一个错误:

bool MyMessageBox::event(QEvent* e)

    bool result = QMessageBox::event(e);
    // force resizing back on, QMessageBox keeps turning it off:
    if (maximumWidth() != QWIDGETSIZE_MAX) 
        QTextEdit *textEdit = findChild<QTextEdit*>();
        if (textEdit && textEdit->isVisible()) 
            textEdit->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
            textEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
            setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
            setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
         else 
            setMaximumWidth(QWIDGETSIZE_MAX);
            setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
        
    
    return result;

【讨论】:

【参考方案4】:

一段时间过去了,但问题仍然有效。

我做了以下实现,在 OSX 和 PySide6 上运行良好,但在其他系统上没有测试。

class MyMessageBox(QMessageBox):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self._width = 150   # default

        self.setSizeGripEnabled(True)

    def setWidth(self, width):
        self._width = width

    def resizeEvent(self, event):
        _result = super().resizeEvent(event)

        self.setFixedWidth(self._width)

        _text_box = self.findChild(QTextEdit)
        if _text_box is not None:
            # get width
            _width = int(self._width - 50)  # - 50 for border area
            # get box height depending on content
            _font = _text_box.document().defaultFont()
            _fontMetrics = QFontMetrics(_font)
            _textSize = _fontMetrics.size(0, details_box.toPlainText(), 0)
            _height = int(_textSize.height()) + 30  # Need to tweak
            # set size
            _text_box.setFixedSize(_width, _height)

        return _result

通话结束:

    _msg_box = MyMessageBox(parent=self)
    _msg_box.setIcon(icon)
    _msg_box.setText(title_text)
    _msg_box.setInformativeText(message)
    _msg_box.setDetailedText(detailed_text)

    # define a reference width and apply it
    _width = int(self.geometry().width() / 2.5)
    _msg_box.setWidth(_width)

    _msg_box.exec()

这样,默认宽度设置为 150,但可能会通过 setWidth 方法进行更改。高度是自动设置的。 如果提供了详细的文本,则文本框的宽度会比消息框本身的总宽度小一点(- 50),高度取决于内容。

注意我没有在文本框中使用较大的内容。

【讨论】:

以上是关于如何允许在 PyQt4 中调整 QMessageBox 的大小的主要内容,如果未能解决你的问题,请参考以下文章

如何用鼠标动态调整 QHBoxLayout 和 QGraphicsView 大小? (Python,Pyqt4)

PyQt4:如何/何时从 QTabWidget 的子类发出自定义信号?

PyQt4:将QGraphicsItem调整为固定的QRectF

PyQt4 中的滑块

用鼠标调整 QGraphicsItem 的大小

如何在 spynner/PyQt4 中设置应用程序名称?