在 QSplitter PyQt 应用程序中设置 QTabWidget 的初始大小

Posted

技术标签:

【中文标题】在 QSplitter PyQt 应用程序中设置 QTabWidget 的初始大小【英文标题】:Setting initial size of QTabWidget in QSplitter PyQt application 【发布时间】:2017-12-13 08:37:45 【问题描述】:

我有一个垂直拆分器,顶部有一个 QTabWidget,下面有一个 QPlainTextEdit 小部件(用作日志窗口)。在实际应用中,选项卡中充满了 QWidget,包含一个 matplotlib 画布和一个带有一些控制元素的 QFrame:

    QSplitter
      QPlainTextEdit
      QVBoxLayout
        QTabWidget
          QWidget
            QVBoxLayout
              FigureCanvas (QSizePolicy.Expanding, QSizePolicy.Expanding)
              QFrame (optional)

我希望应用程序在选项卡和日志记录窗口之间以 4:1 的垂直比例开始。但是,在这里使用mysplitter.setStretchFactor(4,1) 不起作用,因为QTabWidget 的sizeHint() 仅是(4,4),导致带有sizeHint() = (256,192) 的QPlainTextEdit 吞噬几乎所有可用的垂直空间。作为一种解决方法,我目前正在为 QPlainTextWidget 设置固定高度,但我知道这个小部件不是罪魁祸首。

我想我需要摆弄 sizePolicies 或各个选项卡的布局/大小,但到目前为止我还没有成功。我已附上 MWE,完整代码可在 https://github.com/chipmuenk/pyFDA/blob/master/pyfda/pyfdax.py 获得:

# -*- coding: utf-8 -*-
from __future__ import print_function
from PyQt5.QtWidgets import (QWidget, QTabWidget, QPlainTextEdit, QSplitter, 
                             QMainWindow, QVBoxLayout, QApplication)
from PyQt5.QtGui import QFontMetrics
from PyQt5 import QtCore

#------------------------------------------------------------------------------
class TabWidgets(QTabWidget):
    def __init__(self, parent):
        super(TabWidgets, self).__init__(parent)
        self.wdg1 = QWidget(self)
        self.wdg2 = QWidget(self)
        self._construct_UI()
#------------------------------------------------------------------------------
    def _construct_UI(self):
        """ Initialize UI with tabbed subplots """
        self.tabWidget = QTabWidget(self)
        self.tabWidget.addTab(self.wdg1, 'Wdg 1')
        self.tabWidget.addTab(self.wdg2, 'Wdg 2')

        layVMain = QVBoxLayout()
        layVMain.addWidget(self.tabWidget)
        self.setLayout(layVMain)
        # When user has switched the tab, call self.current_tab_redraw
        self.tabWidget.currentChanged.connect(self.current_tab_redraw)
#------------------------------------------------------------------------------

    def current_tab_redraw(self):
        pass
        #self.tabWidget.currentWidget().resize()

class MWin(QMainWindow):
    """
    Main window consisting of a tabbed widget and a status window.
    QMainWindow is used as it understands GUI elements like central widget
    """
    def __init__(self, parent=None):
        super(QMainWindow,self).__init__()
 #---------------------------------------------------------------       
        statusWin = QPlainTextEdit(self)  # status window
        tabWin    = TabWidgets(self) # tabbed window
        print('size status win: 0'.format(statusWin.sizeHint()))
        print('size_tab win: 0'.format(tabWin.sizeHint()))
        mSize = QFontMetrics(statusWin.font())
        rowHt = mSize.lineSpacing()
        # fixed height for statusWin needed as the sizeHint of tabWin is very small
        statusWin.setFixedHeight(4*rowHt+4)
        # add status window underneath plot Tab Widgets:
        spltVMain = QSplitter(QtCore.Qt.Vertical)
        spltVMain.addWidget(tabWin)
        spltVMain.addWidget(statusWin)
        # relative initial sizes of subwidgets, this doesn't work here
        spltVMain.setStretchFactor(4,1)        

        spltVMain.setFocus()
        # make spltVMain occupy the main area of QMainWindow and set inheritance
        self.setCentralWidget(spltVMain)   
#----------------------------------------------------------------------------
def main():
    import sys
    app = QApplication(sys.argv)

    mainw = MWin(None)
    mainw.resize(300,400)
    app.setActiveWindow(mainw) 
    mainw.show()

    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

【问题讨论】:

【参考方案1】:

我找到了一个简单的解决方法:将拆分器设置为绝对单位而不是比率就可以了。说明拆分器小部件的总高度,使解决方案适用于不同的分辨率等。下面的代码 sn-p 显示了更新的 __init__() 部分:

def __init__(self, parent=None):
    super(QMainWindow,self).__init__()
    #---------------------------------------------------------------       
    statusWin = QPlainTextEdit(self)  # status window
    tabWin    = TabWidgets(self) # tabbed window
    print('size status win: 0'.format(statusWin.sizeHint()))
    print('size_tab win: 0'.format(tabWin.sizeHint()))
    # fixed height for statusWin no longer needed here
    # mSize = QFontMetrics(statusWin.font())
    # rowHt = mSize.lineSpacing()
    # statusWin.setFixedHeight(4*rowHt+4)
    # add status window underneath plot Tab Widgets:
    spltVMain = QSplitter(QtCore.Qt.Vertical)
    spltVMain.addWidget(tabWin)
    spltVMain.addWidget(statusWin)
    # relative initial sizes of subwidgets, this doesn't work here
    # spltVMain.setStretchFactor(4,1)
    # Use absolute values instead:
    spltVMain.setSizes([spltVMain.size().height() * 0.8, 
                        spltVMain.size().height() * 0.2])

    spltVMain.setFocus()
    # make spltVMain occupy the main area of QMainWindow and set inheritance
    self.setCentralWidget(spltVMain)   
#-----------------------------------------------------------------------

【讨论】:

以上是关于在 QSplitter PyQt 应用程序中设置 QTabWidget 的初始大小的主要内容,如果未能解决你的问题,请参考以下文章

使用 fbs 时无法在 pyqt5 中设置图标

如何使 PyQt QSplitter 可见?

PyQt5 学习记录010:QSplitter

在pyqt5中设置显示窗口的代码是啥?

如何在 Pyqt4 中设置 QTableView 标头名称

如何在 PyQt5 中设置 QTableWidget 的单元格样式?