PyQt - 手动调整菜单小部件的大小不会调整其内容的大小

Posted

技术标签:

【中文标题】PyQt - 手动调整菜单小部件的大小不会调整其内容的大小【英文标题】:PyQt - Manually resizing menu widget does not resize its content 【发布时间】:2016-10-19 16:12:48 【问题描述】:

我正在使用 QToolButton 打开一个菜单,这是一个简单的 QWidget。在这个小部件内有一个 QTextEdit 和一个按钮。在右下角有一个 QSizeGrip,我想用它来让用户调整小部件的大小,从而调整 QTextEdit。

如果我在 MainWindow (Option1) 中单独使用这个小部件,一切都会按预期工作。但是,如果我将此小部件放入菜单 (Option2),我将无法再调整它的大小。拖动 QSizeGrip 会更改 Menu 的大小,但不会更改 Widget。我已经尝试过setWindowFlags(QtCore.Qt.SubWindow)setSizePolicy(..) 没有任何明显的效果。

我的问题是:如何使小部件(连同 TextEdit)可调整大小?

这是代码,下面是一张图片。

import sys
from PyQt4 import QtGui, QtCore

class MyWidget(QtGui.QWidget):
    def __init__(self, parent=None):
        super(MyWidget, self).__init__(parent)

        self.setLayout(QtGui.QVBoxLayout())
        self.TextEdit = QtGui.QTextEdit()

        self.Button = QtGui.QPushButton("Push")

        self.UpdateWidget = QtGui.QWidget()
        self.UpdateWidget.setLayout(QtGui.QHBoxLayout())
        self.UpdateWidget.layout().addWidget(self.Button, 1)
        self.UpdateWidget.layout().addWidget(QtGui.QSizeGrip(self), 0)

        self.layout().addWidget(self.TextEdit)
        self.layout().addWidget(self.UpdateWidget)

        self.layout().setSpacing(0)
        self.layout().setContentsMargins(0,0,0,0)
        self.UpdateWidget.layout().setSpacing(4)
        self.UpdateWidget.layout().setContentsMargins(0,0,0,0)

        # This is what I already tried to make the menu resizable:
        #self.setWindowFlags(QtCore.Qt.SubWindow)
        #self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
        #self.TextEdit.setWindowFlags(QtCore.Qt.SubWindow)
        #self.TextEdit.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)


class ToolBar(QtGui.QWidget):
    def __init__(self, parent=None):
        super(ToolBar, self).__init__(parent)
        self.setLayout(QtGui.QHBoxLayout())
        self.Button = QtGui.QToolButton()
        self.Button.setText("Open Text Editor")
        self.Button.setPopupMode(QtGui.QToolButton.InstantPopup)
        self.Button.setMenu(QtGui.QMenu(self.Button))
        action = QtGui.QWidgetAction(self.Button)
        action.setDefaultWidget(MyWidget())
        self.Button.menu().addAction(action)
        self.layout().addWidget(self.Button)


class App(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(App, self).__init__(parent)

        #Option 1: 
        #Use MyWidget in MainWindow. This works as expected.
        #self.central = MyWidget()

        #Option 2:
        #Use MyWidget as default widgt for a menu action. 
        #In this case MyWidget cannot be resized.
        self.central = ToolBar()

        self.setCentralWidget(self.central)


if __name__=='__main__':
    app = QtGui.QApplication(sys.argv)
    thisapp = App()
    thisapp.show()
    sys.exit(app.exec_())

【问题讨论】:

【参考方案1】:

问题是因为Button.menu 没有通知您的小部件尺寸变化。

在工具栏中,您可以将自己的函数分配给resizeEvent,这将调整您的小部件的大小。

您需要访问您的小部件

    self.MyW = MyWidget()

你可以分配自己的功能

    self.Button.menu().resizeEvent = self.onResize

def onResize(self, event):        
    self.MyW.resize(event.size())

完整代码:

import sys
from PyQt4 import QtGui, QtCore

class MyWidget(QtGui.QWidget):

    def __init__(self, parent=None):
        super(MyWidget, self).__init__(parent)    
        self.setLayout(QtGui.QVBoxLayout())

        self.TextEdit = QtGui.QTextEdit()

        self.Button = QtGui.QPushButton("Push")

        self.UpdateWidget = QtGui.QWidget()
        self.UpdateWidget.setLayout(QtGui.QHBoxLayout())
        self.UpdateWidget.layout().addWidget(self.Button, 1)
        self.UpdateWidget.layout().addWidget(QtGui.QSizeGrip(self), 0)

        self.layout().addWidget(self.TextEdit)
        self.layout().addWidget(self.UpdateWidget)

        self.layout().setSpacing(0)
        self.layout().setContentsMargins(0,0,0,0)
        self.UpdateWidget.layout().setSpacing(4)
        self.UpdateWidget.layout().setContentsMargins(0,0,0,0)


class ToolBar(QtGui.QWidget):

    def __init__(self, parent=None):
        super(ToolBar, self).__init__(parent)
        self.setLayout(QtGui.QHBoxLayout())

        self.Button = QtGui.QToolButton()
        self.Button.setText("Open Text Editor")
        self.Button.setPopupMode(QtGui.QToolButton.InstantPopup)
        self.Button.setMenu(QtGui.QMenu(self.Button))

        self.MyW = MyWidget() # <-- here
        action = QtGui.QWidgetAction(self.Button) 
        action.setDefaultWidget(self.MyW) # <-- here

        self.Button.menu().addAction(action)
        self.layout().addWidget(self.Button)

        self.Button.menu().resizeEvent = self.onResize # <-- here

    def onResize(self, event):        # <-- here
        self.MyW.resize(event.size()) # <-- here

class App(QtGui.QMainWindow):

    def __init__(self, parent=None):
        super(App, self).__init__(parent)

        #Option 1: 
        #Use MyWidget in MainWindow. This works as expected.
        #self.central = MyWidget()

        #Option 2:
        #Use MyWidget as default widgt for a menu action. 
        #In this case MyWidget cannot be resized.
        self.central = ToolBar()

        self.setCentralWidget(self.central)


if __name__=='__main__':
    app = QtGui.QApplication(sys.argv)
    thisapp = App()
    thisapp.show()
    sys.exit(app.exec_())

也许可以用SizeGripMyWidget 完成,但我没有尝试

【讨论】:

以上是关于PyQt - 手动调整菜单小部件的大小不会调整其内容的大小的主要内容,如果未能解决你的问题,请参考以下文章

PyQt5,让用户调整小部件的大小

Pyqt QMdiSubWindow 使用可变数量的小部件调整大小

PyQt 中的半可调整大小的小部件

调整列宽以适应 QTableWidget pyqt

控制PyQt QFormLayout中的Widget放置

PyQt5:创建强制固定高度的流布局