【问题标题】:How to dynamically add items into QHorizontal layout without affecting window size or other items in the layout?如何在不影响窗口大小或布局中其他项目的情况下将项目动态添加到 QHorizo​​ntal 布局中?
【发布时间】:2020-04-13 18:10:51
【问题描述】:

我有一个水平布局,其中包含用于搜索/过滤 TableView 的各种工具栏。用户应该从前两个组合框中选择一列和一个运算符,在文本字段中输入一个搜索短语,然后点击搜索按钮来过滤表格。有一个“重置”按钮可以清除所有添加的过滤器,然后有一个水平分隔符将这组小部件与右侧的“绘图”按钮分开。

看起来像这样

小部件的所有大小策略都设置为“最小”,除了文本字段(扩展)和水平分隔符(忽略)。

我想在“重置”按钮的右侧添加一个 QLabel,用于汇总刚刚添加的过滤器,如下所示。

问题是,我的水平间隔不会缩小以允许 QLabel 占用空间,因此整个窗口都会调整大小。这是一个问题,因为我已经实现了“堆叠”过滤器,并希望向用户显示添加到表中的每个过滤器。

理想情况下,随着越来越多的过滤器被添加,我希望 QLabels 缩小水平间隔直到它有效地消失,然后让它们均匀地缩小自己以适应“重置”按钮和“绘图”之间的空间按钮。我从不希望 QLabels 影响整个窗口大小。

我尝试将水平间隔的大小策略设置为忽略、最小和最大,并且它不会影响任何东西,即添加 QLabels 时,整个窗口会变大以适应它们。我也尝试过水平分隔符退出布局,插入 QLabel,然后重新添加分隔符以“刷新”水平布局(如 this 论坛帖子中所建议的那样)。

exampleUI.py(使用 pyuic5 自动生成):

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'example.ui'
#
# Created by: PyQt5 UI code generator 5.12.1
#
# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(1538, 843)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.horizontalLayout_5 = QtWidgets.QHBoxLayout(self.centralwidget)
        self.horizontalLayout_5.setObjectName("horizontalLayout_5")
        self.splitter_2 = QtWidgets.QSplitter(self.centralwidget)
        self.splitter_2.setOrientation(QtCore.Qt.Horizontal)
        self.splitter_2.setObjectName("splitter_2")
        self.treeWidget = QtWidgets.QTreeWidget(self.splitter_2)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(5)
        sizePolicy.setVerticalStretch(1)
        sizePolicy.setHeightForWidth(self.treeWidget.sizePolicy().hasHeightForWidth())
        self.treeWidget.setSizePolicy(sizePolicy)
        self.treeWidget.setObjectName("treeWidget")
        item_0 = QtWidgets.QTreeWidgetItem(self.treeWidget)
        item_0 = QtWidgets.QTreeWidgetItem(self.treeWidget)
        item_0 = QtWidgets.QTreeWidgetItem(self.treeWidget)
        item_0 = QtWidgets.QTreeWidgetItem(self.treeWidget)
        item_0 = QtWidgets.QTreeWidgetItem(self.treeWidget)
        self.splitter = QtWidgets.QSplitter(self.splitter_2)
        self.splitter.setOrientation(QtCore.Qt.Vertical)
        self.splitter.setObjectName("splitter")
        self.Widget = QtWidgets.QWidget(self.splitter)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(1)
        sizePolicy.setVerticalStretch(4)
        sizePolicy.setHeightForWidth(self.Widget.sizePolicy().hasHeightForWidth())
        self.Widget.setSizePolicy(sizePolicy)
        self.Widget.setObjectName("Widget")
        self.tabWidget = QtWidgets.QTabWidget(self.splitter)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(2)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.tabWidget.sizePolicy().hasHeightForWidth())
        self.tabWidget.setSizePolicy(sizePolicy)
        self.tabWidget.setObjectName("tabWidget")
        self.tab_2 = QtWidgets.QWidget()
        self.tab_2.setObjectName("tab_2")
        self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.tab_2)
        self.horizontalLayout_3.setObjectName("horizontalLayout_3")
        self.verticalLayout_2 = QtWidgets.QVBoxLayout()
        self.verticalLayout_2.setObjectName("verticalLayout_2")
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        self.columnComboBox_2 = QtWidgets.QComboBox(self.tab_2)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(1)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.columnComboBox_2.sizePolicy().hasHeightForWidth())
        self.columnComboBox_2.setSizePolicy(sizePolicy)
        self.columnComboBox_2.setObjectName("columnComboBox_2")
        self.columnComboBox_2.addItem("")
        self.columnComboBox_2.addItem("")
        self.columnComboBox_2.addItem("")
        self.columnComboBox_2.addItem("")
        self.columnComboBox_2.addItem("")
        self.columnComboBox_2.addItem("")
        self.columnComboBox_2.addItem("")
        self.horizontalLayout_2.addWidget(self.columnComboBox_2)
        self.operatorComboBox_2 = QtWidgets.QComboBox(self.tab_2)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.operatorComboBox_2.sizePolicy().hasHeightForWidth())
        self.operatorComboBox_2.setSizePolicy(sizePolicy)
        self.operatorComboBox_2.setObjectName("operatorComboBox_2")
        self.operatorComboBox_2.addItem("")
        self.operatorComboBox_2.addItem("")
        self.operatorComboBox_2.addItem("")
        self.operatorComboBox_2.addItem("")
        self.operatorComboBox_2.addItem("")
        self.operatorComboBox_2.addItem("")
        self.horizontalLayout_2.addWidget(self.operatorComboBox_2)
        self.FilterBar_2 = QtWidgets.QLineEdit(self.tab_2)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(3)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.FilterBar_2.sizePolicy().hasHeightForWidth())
        self.FilterBar_2.setSizePolicy(sizePolicy)
        self.FilterBar_2.setObjectName("FilterBar_2")
        self.horizontalLayout_2.addWidget(self.FilterBar_2)
        self.SearchButton_2 = QtWidgets.QPushButton(self.tab_2)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.SearchButton_2.sizePolicy().hasHeightForWidth())
        self.SearchButton_2.setSizePolicy(sizePolicy)
        self.SearchButton_2.setObjectName("SearchButton_2")
        self.horizontalLayout_2.addWidget(self.SearchButton_2)
        self.resetFilterButton_2 = QtWidgets.QPushButton(self.tab_2)
        self.resetFilterButton_2.setObjectName("resetFilterButton_2")
        self.horizontalLayout_2.addWidget(self.resetFilterButton_2)
        spacerItem = QtWidgets.QSpacerItem(800, 20, QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_2.addItem(spacerItem)
        self.pushButton_2 = QtWidgets.QPushButton(self.tab_2)
        self.pushButton_2.setObjectName("pushButton_2")
        self.horizontalLayout_2.addWidget(self.pushButton_2)
        self.verticalLayout_2.addLayout(self.horizontalLayout_2)
        self.tableView_2 = QtWidgets.QTableView(self.tab_2)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(2)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.tableView_2.sizePolicy().hasHeightForWidth())
        self.tableView_2.setSizePolicy(sizePolicy)
        self.tableView_2.setObjectName("tableView_2")
        self.verticalLayout_2.addWidget(self.tableView_2)
        self.horizontalLayout_3.addLayout(self.verticalLayout_2)
        self.tabWidget.addTab(self.tab_2, "")
        self.horizontalLayout_5.addWidget(self.splitter_2)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 1538, 26))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        self.tabWidget.setCurrentIndex(0)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.treeWidget.headerItem().setText(0, _translate("MainWindow", "Account"))
        self.treeWidget.headerItem().setText(1, _translate("MainWindow", "Balance"))
        __sortingEnabled = self.treeWidget.isSortingEnabled()
        self.treeWidget.setSortingEnabled(False)
        self.treeWidget.topLevelItem(0).setText(0, _translate("MainWindow", "Cash"))
        self.treeWidget.topLevelItem(1).setText(0, _translate("MainWindow", "Credit"))
        self.treeWidget.topLevelItem(2).setText(0, _translate("MainWindow", "Investments"))
        self.treeWidget.topLevelItem(3).setText(0, _translate("MainWindow", "Loans"))
        self.treeWidget.topLevelItem(4).setText(0, _translate("MainWindow", "Property"))
        self.treeWidget.setSortingEnabled(__sortingEnabled)
        self.columnComboBox_2.setItemText(0, _translate("MainWindow", "Column:"))
        self.columnComboBox_2.setItemText(1, _translate("MainWindow", "Date"))
        self.columnComboBox_2.setItemText(2, _translate("MainWindow", "Merchant"))
        self.columnComboBox_2.setItemText(3, _translate("MainWindow", "Category"))
        self.columnComboBox_2.setItemText(4, _translate("MainWindow", "Amount"))
        self.columnComboBox_2.setItemText(5, _translate("MainWindow", "Account"))
        self.columnComboBox_2.setItemText(6, _translate("MainWindow", "F.I."))
        self.operatorComboBox_2.setItemText(0, _translate("MainWindow", "="))
        self.operatorComboBox_2.setItemText(1, _translate("MainWindow", "<"))
        self.operatorComboBox_2.setItemText(2, _translate("MainWindow", ">"))
        self.operatorComboBox_2.setItemText(3, _translate("MainWindow", "<="))
        self.operatorComboBox_2.setItemText(4, _translate("MainWindow", ">="))
        self.operatorComboBox_2.setItemText(5, _translate("MainWindow", "NOT"))
        self.FilterBar_2.setPlaceholderText(_translate("MainWindow", "Filter transactions..."))
        self.SearchButton_2.setText(_translate("MainWindow", "Search"))
        self.resetFilterButton_2.setText(_translate("MainWindow", "Reset"))
        self.pushButton_2.setText(_translate("MainWindow", "Plot"))
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("MainWindow", "Transactions"))




if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

exampleApp.py(应用程序类:)

from exampleUI import Ui_MainWindow
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QSizePolicy
import sys

class exampleApp:

    def __init__(self):
        # Initialize QtWidgets
        self.MainWindow = QtWidgets.QMainWindow()

        # Initialize UI objects
        self.MainWindowUi = Ui_MainWindow()

        # Plug QtWidget object into setupUi method of UI object
        self.MainWindowUi.setupUi(self.MainWindow)

        self.MainWindow.show()

        self.MainWindowUi.SearchButton_2.clicked.connect(lambda: self.add_filter(
            self.MainWindowUi.columnComboBox_2.currentText(), self.MainWindowUi.operatorComboBox_2.currentText(),
            self.MainWindowUi.FilterBar_2.text()))

    def add_filter(self, column, operator, phrase):
        filter_string = "{} {} {}".format(column, operator, phrase)

        label = QtWidgets.QLabel(filter_string)
        label.setToolTip(filter_string)
        label.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed)
        self.MainWindowUi.horizontalLayout_2.insertWidget(5, label, 0)


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    ui = exampleApp()
    sys.exit(app.exec())

example.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>1538</width>
    <height>843</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QHBoxLayout" name="horizontalLayout_5">
    <item>
     <widget class="QSplitter" name="splitter_2">
      <property name="orientation">
       <enum>Qt::Horizontal</enum>
      </property>
      <widget class="QTreeWidget" name="treeWidget">
       <property name="sizePolicy">
        <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
         <horstretch>5</horstretch>
         <verstretch>1</verstretch>
        </sizepolicy>
       </property>
       <column>
        <property name="text">
         <string>Account</string>
        </property>
       </column>
       <column>
        <property name="text">
         <string>Balance</string>
        </property>
       </column>
       <item>
        <property name="text">
         <string>Cash</string>
        </property>
       </item>
       <item>
        <property name="text">
         <string>Credit</string>
        </property>
       </item>
       <item>
        <property name="text">
         <string>Investments</string>
        </property>
       </item>
       <item>
        <property name="text">
         <string>Loans</string>
        </property>
       </item>
       <item>
        <property name="text">
         <string>Property</string>
        </property>
       </item>
      </widget>
      <widget class="QSplitter" name="splitter">
       <property name="orientation">
        <enum>Qt::Vertical</enum>
       </property>
       <widget class="QWidget" name="Widget" native="true">
        <property name="sizePolicy">
         <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
          <horstretch>1</horstretch>
          <verstretch>4</verstretch>
         </sizepolicy>
        </property>
       </widget>
       <widget class="QTabWidget" name="tabWidget">
        <property name="sizePolicy">
         <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
          <horstretch>2</horstretch>
          <verstretch>0</verstretch>
         </sizepolicy>
        </property>
        <property name="currentIndex">
         <number>0</number>
        </property>
        <widget class="QWidget" name="tab_2">
         <attribute name="title">
          <string>Transactions</string>
         </attribute>
         <layout class="QHBoxLayout" name="horizontalLayout_3">
          <item>
           <layout class="QVBoxLayout" name="verticalLayout_2">
            <item>
             <layout class="QHBoxLayout" name="horizontalLayout_2">
              <item>
               <widget class="QComboBox" name="columnComboBox_2">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
                  <horstretch>1</horstretch>
                  <verstretch>0</verstretch>
                 </sizepolicy>
                </property>
                <item>
                 <property name="text">
                  <string>Column:</string>
                 </property>
                </item>
                <item>
                 <property name="text">
                  <string>Date</string>
                 </property>
                </item>
                <item>
                 <property name="text">
                  <string>Merchant</string>
                 </property>
                </item>
                <item>
                 <property name="text">
                  <string>Category</string>
                 </property>
                </item>
                <item>
                 <property name="text">
                  <string>Amount</string>
                 </property>
                </item>
                <item>
                 <property name="text">
                  <string>Account</string>
                 </property>
                </item>
                <item>
                 <property name="text">
                  <string>F.I.</string>
                 </property>
                </item>
               </widget>
              </item>
              <item>
               <widget class="QComboBox" name="operatorComboBox_2">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
                  <horstretch>0</horstretch>
                  <verstretch>0</verstretch>
                 </sizepolicy>
                </property>
                <item>
                 <property name="text">
                  <string>=</string>
                 </property>
                </item>
                <item>
                 <property name="text">
                  <string>&lt;</string>
                 </property>
                </item>
                <item>
                 <property name="text">
                  <string>&gt;</string>
                 </property>
                </item>
                <item>
                 <property name="text">
                  <string>&lt;=</string>
                 </property>
                </item>
                <item>
                 <property name="text">
                  <string>&gt;=</string>
                 </property>
                </item>
                <item>
                 <property name="text">
                  <string>NOT</string>
                 </property>
                </item>
               </widget>
              </item>
              <item>
               <widget class="QLineEdit" name="FilterBar_2">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
                  <horstretch>3</horstretch>
                  <verstretch>0</verstretch>
                 </sizepolicy>
                </property>
                <property name="placeholderText">
                 <string>Filter transactions...</string>
                </property>
               </widget>
              </item>
              <item>
               <widget class="QPushButton" name="SearchButton_2">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
                  <horstretch>0</horstretch>
                  <verstretch>0</verstretch>
                 </sizepolicy>
                </property>
                <property name="text">
                 <string>Search</string>
                </property>
               </widget>
              </item>
              <item>
               <widget class="QPushButton" name="resetFilterButton_2">
                <property name="text">
                 <string>Reset</string>
                </property>
               </widget>
              </item>
              <item>
               <spacer name="horizontalSpacer_2">
                <property name="orientation">
                 <enum>Qt::Horizontal</enum>
                </property>
                <property name="sizeType">
                 <enum>QSizePolicy::Ignored</enum>
                </property>
                <property name="sizeHint" stdset="0">
                 <size>
                  <width>800</width>
                  <height>20</height>
                 </size>
                </property>
               </spacer>
              </item>
              <item>
               <widget class="QPushButton" name="pushButton_2">
                <property name="text">
                 <string>Plot</string>
                </property>
               </widget>
              </item>
             </layout>
            </item>
            <item>
             <widget class="QTableView" name="tableView_2">
              <property name="sizePolicy">
               <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
                <horstretch>2</horstretch>
                <verstretch>0</verstretch>
               </sizepolicy>
              </property>
             </widget>
            </item>
           </layout>
          </item>
         </layout>
        </widget>
       </widget>
      </widget>
     </widget>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>1538</width>
     <height>26</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>

对于冗长的 UI 文件深表歉意,但我认为捕获所有嵌套布局交互以确保了解我的情况很重要。 exampleApp.py 被最小化,只关注这个问题。

运行 exampleApp.py,然后在文本字段中输入一些内容并从组合框中选择几个选项,然后多次按“搜索”按钮将在水平布局中插入几个标签并演示我的问题。

有人对我如何实现这一点有任何想法吗?

【问题讨论】:

  • @eyllanesc 感谢您的建议,我添加了一个可重现的最小示例来演示我的问题。
  • 请分享.ui
  • @eyllanesc 在帖子中添加了指向 .ui 文件的链接

标签: python pyqt pyqt5


【解决方案1】:

您(就像我们中的许多人一样)可能对Minimum 大小政策的概念感到困惑。该文档在技术上没有错误(但它令人困惑),您“只”需要一些关注和理解才能获得它。

Minimum”并不意味着小部件将其尺寸提示用作“最小”尺寸,而是尺寸提示«最小»(“hint”是关键字:这是一个“建议”)。
您正在寻找的实际上是Maximum:«小部件可以缩小任何数量»«不能大于 sizeHint() 提供的大小»,它设置了 ShrinkFlag。据此,您可能最终也会得到GrowFlag(这可确保小部件在必要时可以“增长”);这将带您使用Preferred sizePolicy,这是大多数 QWidgets 的默认值。仔细阅读QSizePolicy documentation,并自己做一些测试以更好地理解它;这需要一些时间和大量的关注,但这是值得的。

所以,长话短说:不要为 any 小部件设置 Minimum sizePolicy(除非确实需要)。改为保留默认的Preferred 策略,如果没有将Expanding 设置为默认大小策略,则将Expanding 用于需要“消耗”所有可用空间的任何其他小部件。
在您的特定情况下(至少,根据您的问题),重置tabWidget 的默认策略可能就足够了,这两个方向都是Expanded(但我建议您“撤消”小部件属性而不是手动设置)。

【讨论】:

    猜你喜欢
    • 2021-03-29
    • 2021-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多