【问题标题】:How to make the QPushButtons and ToolBox Tabs expand to 100% width如何使 QPushButtons 和 ToolBox 选项卡扩展为 100% 宽度
【发布时间】:2022-01-25 11:35:21
【问题描述】:

我正在尝试在 PyQt 中创建一个侧边菜单,类似于:https://www.youtube.com/watch?v=O9l75KOB2pE

为了在菜单中创建“子菜单”,我选择了“工具箱”,然后在工具箱之后添加了一个 QPushButton(这将是子菜单下方的单个按钮。它也有助于“未打开”子菜单不会转到帧的末尾)

但是,我在这样做时遇到了多个问题。在视频中,他在每个按钮下方添加了一个border-bottom,并在按钮悬停时添加了一个border-left。

我也这样做了,但显然我的按钮没有完全展开,因此边框底部仅添加在 QPushButton 的“文本”下方,而不是整个菜单下方。同样,左边框被添加到 QPushButton 文本的最左侧(而不是侧边菜单的左侧)。

此外,工具箱的选项卡也被缩小了(即其中不显示全文。这也可能是因为它没有获得侧边菜单框架的整个宽度)

我尝试使用不同小部件的“SizePolicy”以某种方式使按钮在宽度上完全展开,但对我来说没有任何效果。谁能帮我解决这个问题?

这是我当前程序的 .ui 代码,

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="windowModality">
   <enum>Qt::NonModal</enum>
  </property>
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>1074</width>
    <height>751</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <property name="styleSheet">
   <string notr="true">* {
border: none;
}

.QTableWidget
{
alternate-background-color: rgb(241, 241, 241);
background-color: white;
}

.QTableWidget:item
{
color: black;
padding: 5px;
}

.QHeaderView::section
{
background-color: white;
color: black;
font-weight: bold;
border: 0px;
border-bottom: 1px solid;
}</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <property name="styleSheet">
    <string notr="true">background-color: white;</string>
   </property>
   <layout class="QHBoxLayout" name="horizontalLayout">
    <property name="leftMargin">
     <number>0</number>
    </property>
    <property name="topMargin">
     <number>0</number>
    </property>
    <property name="rightMargin">
     <number>0</number>
    </property>
    <property name="bottomMargin">
     <number>0</number>
    </property>
    <item>
     <widget class="QFrame" name="side_menu_container">
      <property name="maximumSize">
       <size>
        <width>230</width>
        <height>16777215</height>
       </size>
      </property>
      <property name="styleSheet">
       <string notr="true">background-color: #1b1b1b;
color: white;
font-size: 25px;
font-weight: 600;
line-height: 65px;
text-align: center;
letter-spacing: 1px;

</string>
      </property>
      <property name="frameShape">
       <enum>QFrame::StyledPanel</enum>
      </property>
      <property name="frameShadow">
       <enum>QFrame::Raised</enum>
      </property>
      <layout class="QVBoxLayout" name="verticalLayout_2">
       <property name="leftMargin">
        <number>0</number>
       </property>
       <property name="topMargin">
        <number>6</number>
       </property>
       <property name="rightMargin">
        <number>0</number>
       </property>
       <property name="bottomMargin">
        <number>0</number>
       </property>
       <item alignment="Qt::AlignTop">
        <widget class="QFrame" name="frame">
         <property name="frameShape">
          <enum>QFrame::StyledPanel</enum>
         </property>
         <property name="frameShadow">
          <enum>QFrame::Raised</enum>
         </property>
         <layout class="QHBoxLayout" name="horizontalLayout_42">
          <property name="spacing">
           <number>0</number>
          </property>
          <property name="topMargin">
           <number>0</number>
          </property>
          <property name="rightMargin">
           <number>0</number>
          </property>
          <property name="bottomMargin">
           <number>0</number>
          </property>
          <item alignment="Qt::AlignLeft|Qt::AlignTop">
           <widget class="QFrame" name="frame_46">
            <property name="styleSheet">
             <string notr="true">font-size: 21px;
</string>
            </property>
            <property name="frameShape">
             <enum>QFrame::StyledPanel</enum>
            </property>
            <property name="frameShadow">
             <enum>QFrame::Raised</enum>
            </property>
            <layout class="QVBoxLayout" name="verticalLayout_4">
             <property name="spacing">
              <number>0</number>
             </property>
             <property name="leftMargin">
              <number>0</number>
             </property>
             <property name="topMargin">
              <number>0</number>
             </property>
             <property name="rightMargin">
              <number>0</number>
             </property>
             <property name="bottomMargin">
              <number>0</number>
             </property>
             <item alignment="Qt::AlignLeft|Qt::AlignTop">
              <widget class="QLabel" name="label_2">
               <property name="font">
                <font>
                 <family>Arial</family>
                 <pointsize>-1</pointsize>
                 <weight>75</weight>
                 <bold>true</bold>
                </font>
               </property>
               <property name="text">
                <string>Timetable Manager</string>
               </property>
              </widget>
             </item>
            </layout>
           </widget>
          </item>
         </layout>
        </widget>
       </item>
       <item>
        <widget class="QFrame" name="frame_45">
         <property name="enabled">
          <bool>true</bool>
         </property>
         <property name="styleSheet">
          <string notr="true">background-color: #1e1e1e;</string>
         </property>
         <property name="frameShape">
          <enum>QFrame::StyledPanel</enum>
         </property>
         <property name="frameShadow">
          <enum>QFrame::Raised</enum>
         </property>
         <layout class="QVBoxLayout" name="verticalLayout_20">
          <property name="spacing">
           <number>0</number>
          </property>
          <property name="leftMargin">
           <number>0</number>
          </property>
          <property name="topMargin">
           <number>0</number>
          </property>
          <property name="rightMargin">
           <number>0</number>
          </property>
          <property name="bottomMargin">
           <number>0</number>
          </property>
          <item>
           <widget class="QFrame" name="side_menu">
            <property name="minimumSize">
             <size>
              <width>228</width>
              <height>0</height>
             </size>
            </property>
            <property name="styleSheet">
             <string notr="true">QPushButton
{
font-size: 16px;
line-height: 60px;
padding: 5px 10px;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
color: #fff; 
border-left: 1px solid transparent;
}

QPushButton:hover
{
color: cyan;
background-color: #1e1e1e;
border-left: 1px solid cyan;
 
}


QToolBox::tab
{
font-size: 15px;
border: none;
}

QToolBox::tab:selected
{
background-color: #1e1e1e;
border-left: 1px solid cyan;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}</string>
            </property>
            <property name="frameShape">
             <enum>QFrame::StyledPanel</enum>
            </property>
            <property name="frameShadow">
             <enum>QFrame::Raised</enum>
            </property>
            <layout class="QVBoxLayout" name="verticalLayout_3">
             <property name="spacing">
              <number>0</number>
             </property>
             <property name="leftMargin">
              <number>0</number>
             </property>
             <property name="topMargin">
              <number>10</number>
             </property>
             <property name="rightMargin">
              <number>0</number>
             </property>
             <property name="bottomMargin">
              <number>0</number>
             </property>
             <item>
              <widget class="QFrame" name="frame_4">
               <property name="sizePolicy">
                <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
                 <horstretch>0</horstretch>
                 <verstretch>0</verstretch>
                </sizepolicy>
               </property>
               <property name="styleSheet">
                <string notr="true"/>
               </property>
               <property name="frameShape">
                <enum>QFrame::StyledPanel</enum>
               </property>
               <property name="frameShadow">
                <enum>QFrame::Raised</enum>
               </property>
               <layout class="QVBoxLayout" name="verticalLayout_5">
                <property name="spacing">
                 <number>0</number>
                </property>
                <property name="leftMargin">
                 <number>0</number>
                </property>
                <property name="topMargin">
                 <number>0</number>
                </property>
                <property name="rightMargin">
                 <number>0</number>
                </property>
                <property name="bottomMargin">
                 <number>0</number>
                </property>
                <item alignment="Qt::AlignLeft|Qt::AlignTop">
                 <widget class="QToolBox" name="toolBox">
                  <property name="styleSheet">
                   <string notr="true"/>
                  </property>
                  <property name="frameShape">
                   <enum>QFrame::NoFrame</enum>
                  </property>
                  <property name="currentIndex">
                   <number>0</number>
                  </property>
                  <widget class="QWidget" name="page_2">
                   <property name="geometry">
                    <rect>
                     <x>0</x>
                     <y>0</y>
                     <width>230</width>
                     <height>201</height>
                    </rect>
                   </property>
                   <property name="styleSheet">
                    <string notr="true"/>
                   </property>
                   <attribute name="icon">
                    <iconset resource="icons.qrc">
                     <normaloff>:/icons/icons/down-arrrow-navigate.png</normaloff>
                     <normalon>:/icons/icons/chevron-down.svg</normalon>:/icons/icons/down-arrrow-navigate.png</iconset>
                   </attribute>
                   <attribute name="label">
                    <string>Registration Details</string>
                   </attribute>
                   <layout class="QVBoxLayout" name="verticalLayout_6">
                    <item alignment="Qt::AlignTop">
                     <widget class="QFrame" name="frame_5">
                      <property name="styleSheet">
                       <string notr="true"/>
                      </property>
                      <property name="frameShape">
                       <enum>QFrame::StyledPanel</enum>
                      </property>
                      <property name="frameShadow">
                       <enum>QFrame::Raised</enum>
                      </property>
                      <layout class="QFormLayout" name="formLayout">
                       <property name="leftMargin">
                        <number>15</number>
                       </property>
                       <property name="rightMargin">
                        <number>0</number>
                       </property>
                       <property name="bottomMargin">
                        <number>0</number>
                       </property>
                       <item row="1" column="0">
                        <widget class="QPushButton" name="course_menu_button">
                         <property name="styleSheet">
                          <string notr="true"/>
                         </property>
                         <property name="text">
                          <string>Courses</string>
                         </property>
                        </widget>
                       </item>
                       <item row="2" column="0">
                        <widget class="QPushButton" name="room_menu_button">
                         <property name="text">
                          <string>Rooms</string>
                         </property>
                        </widget>
                       </item>
                       <item row="3" column="0">
                        <widget class="QPushButton" name="teacher_menu_button">
                         <property name="text">
                          <string>Teachers</string>
                         </property>
                        </widget>
                       </item>
                       <item row="4" column="0">
                        <widget class="QPushButton" name="registered_menu_button">
                         <property name="text">
                          <string>Registered Courses</string>
                         </property>
                        </widget>
                       </item>
                       <item row="0" column="0">
                        <widget class="QPushButton" name="section_menu_button">
                         <property name="sizePolicy">
                          <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
                           <horstretch>0</horstretch>
                           <verstretch>0</verstretch>
                          </sizepolicy>
                         </property>
                         <property name="font">
                          <font>
                           <family>Arial</family>
                           <pointsize>-1</pointsize>
                           <weight>75</weight>
                           <bold>true</bold>
                          </font>
                         </property>
                         <property name="styleSheet">
                          <string notr="true"/>
                         </property>
                         <property name="text">
                          <string>Sections</string>
                         </property>
                         <property name="iconSize">
                          <size>
                           <width>32</width>
                           <height>32</height>
                          </size>
                         </property>
                        </widget>
                       </item>
                      </layout>
                     </widget>
                    </item>
                   </layout>
                  </widget>
                  <widget class="QWidget" name="page_3">
                   <property name="geometry">
                    <rect>
                     <x>0</x>
                     <y>0</y>
                     <width>230</width>
                     <height>102</height>
                    </rect>
                   </property>
                   <attribute name="icon">
                    <iconset resource="icons.qrc">
                     <normaloff>:/icons/icons/chevron-down.svg</normaloff>:/icons/icons/chevron-down.svg</iconset>
                   </attribute>
                   <attribute name="label">
                    <string>Teacher Preferences</string>
                   </attribute>
                   <layout class="QVBoxLayout" name="verticalLayout_13">
                    <item alignment="Qt::AlignTop">
                     <widget class="QFrame" name="frame_32">
                      <property name="frameShape">
                       <enum>QFrame::StyledPanel</enum>
                      </property>
                      <property name="frameShadow">
                       <enum>QFrame::Raised</enum>
                      </property>
                      <layout class="QVBoxLayout" name="verticalLayout_14">
                       <item>
                        <widget class="QPushButton" name="room_preference_menu_button">
                         <property name="text">
                          <string>Room Preferences</string>
                         </property>
                        </widget>
                       </item>
                       <item>
                        <widget class="QPushButton" name="slot_preference_menu_button">
                         <property name="text">
                          <string>Slot Preferences</string>
                         </property>
                        </widget>
                       </item>
                      </layout>
                     </widget>
                    </item>
                   </layout>
                  </widget>
                  <widget class="QWidget" name="page">
                   <property name="geometry">
                    <rect>
                     <x>0</x>
                     <y>0</y>
                     <width>230</width>
                     <height>138</height>
                    </rect>
                   </property>
                   <attribute name="label">
                    <string>Page</string>
                   </attribute>
                   <layout class="QVBoxLayout" name="verticalLayout_17">
                    <item alignment="Qt::AlignTop">
                     <widget class="QFrame" name="frame_43">
                      <property name="frameShape">
                       <enum>QFrame::StyledPanel</enum>
                      </property>
                      <property name="frameShadow">
                       <enum>QFrame::Raised</enum>
                      </property>
                      <layout class="QVBoxLayout" name="verticalLayout_18">
                       <item>
                        <widget class="QPushButton" name="student_clash_menu_button">
                         <property name="text">
                          <string>Student Clashes</string>
                         </property>
                        </widget>
                       </item>
                       <item>
                        <widget class="QPushButton" name="room_clash_menu_button">
                         <property name="text">
                          <string>Room Clashes</string>
                         </property>
                        </widget>
                       </item>
                       <item>
                        <widget class="QPushButton" name="instructor_clash_menu_button">
                         <property name="text">
                          <string>Instructor Clashes</string>
                         </property>
                        </widget>
                       </item>
                      </layout>
                     </widget>
                    </item>
                   </layout>
                  </widget>
                 </widget>
                </item>
               </layout>
              </widget>
             </item>
             <item>
              <widget class="QFrame" name="frame_44">
               <property name="sizePolicy">
                <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
                 <horstretch>0</horstretch>
                 <verstretch>0</verstretch>
                </sizepolicy>
               </property>
               <property name="frameShape">
                <enum>QFrame::StyledPanel</enum>
               </property>
               <property name="frameShadow">
                <enum>QFrame::Raised</enum>
               </property>
               <layout class="QVBoxLayout" name="verticalLayout_19">
                <item alignment="Qt::AlignTop">
                 <widget class="QPushButton" name="pushButton_2">
                  <property name="text">
                   <string>PushButton</string>
                  </property>
                 </widget>
                </item>
               </layout>
              </widget>
             </item>
            </layout>
           </widget>
          </item>
         </layout>
        </widget>
       </item>
      </layout>
     </widget>
    </item>
    <item>
     <widget class="QFrame" name="main_body">
      <property name="frameShape">
       <enum>QFrame::StyledPanel</enum>
      </property>
      <property name="frameShadow">
       <enum>QFrame::Raised</enum>
      </property>
      <layout class="QVBoxLayout" name="verticalLayout">
       <property name="spacing">
        <number>0</number>
       </property>
       <property name="leftMargin">
        <number>0</number>
       </property>
       <property name="topMargin">
        <number>0</number>
       </property>
       <property name="rightMargin">
        <number>0</number>
       </property>
       <property name="bottomMargin">
        <number>0</number>
       </property>
      </layout>
     </widget>
    </item>
   </layout>
  </widget>
 </widget>
 <resources>
  <include location="icons.qrc"/>
 </resources>
 <connections/>
</ui>

【问题讨论】:

    标签: python pyqt pyqt5 qpushbutton qtoolbox


    【解决方案1】:

    提供的 UI 存在各种问题。

    按钮的问题有多种原因,不能从 Designer 轻松解决,尤其是因为您更改了很多属性(其中许多是传播的,包括样式表)。

    首先,左边框是移动的,因为在大多数系统中所有布局都有默认边距,所以你必须显式将它设置为0。

    在 Designer 中,从对象检查器中选择每个 页面,滚动到属性编辑器底部并将 layoutLeftMargin 属性更改为 0。如果该属性已经为 0 但未显示在粗体(表示属性是使用默认值还是显式值),更改为另一个数字,然后再次将其设置为 0。然后对您在该页面中添加的框架执行相同操作.

    第一帧底部边框“不完整”的问题是由于您使用了 QFormLayout,这在某些样式中使按钮仅占用最小尺寸,而不是使它们展开。
    将其改为垂直布局,然后在 QPushButton 选择器的side_menu 样式表中添加以下内容:

    text-align: left;
    

    还要注意,对于如此复杂的小部件结构,您应该小心不要在不同的地方设置太多样式表:这不仅通常是不必要的,而且还难以跟踪它们(在某些时候您可能会遇到一些出乎意料的行为,找到问题的实际根源可能会变得非常困难)。考虑到不要像为side_menu_container 或什至主窗口那样在父级上设置通用样式表属性通常会更好。滚动区域和组合框等复杂的小部件要求,如果您设置属性,则必须设置 all 属性。使用特定的选择器(not 是通配符!)是更好、更安全的选择。另请注意,letter-spacing 不是 QSS 的公认属性,因此您应该删除它。

    应该为顶级小部件(甚至应用程序)设置一个编写良好的样式表,并且只有在 那个小部件实际需要时才为小部件设置一个特定的样式表。

    最后,您在一些小部件中设置了布局对齐,这会阻止它们正确显示,因为设置对齐会导致小部件仅使用其基本尺寸提示,即使有更多可用空间也是如此。

    工具箱按钮的省略文本的问题有点棘手。问题源于 QStyleSheetStyle(一种特殊且私有的 QStyle,在具有样式表或继承样式表的小部件上自动设置)自动使用省略的文本,并且由于样式选项不'没有正确初始化可用的文本矩形。我坚信这是一个错误。

    如果没有设置样式表,解决方案很简单:使用QProxyStyle 并覆盖drawControl 以便自行绘制按钮文本。不幸的是,这对于样式表是不可能的,因为 drawControl 从未被调用,因为它被安装的 QStyleSheetStyle 覆盖。

    但是drawItemText()调用,所以有一个可能的,有点hacky和复杂的解决方案。

    不幸的是,drawItemText() 没有对小部件的引用,因为它仅使用给定选项绘制文本。
    诀窍是为工具箱使用提升的小部件,为其设置自定义代理样式,并覆盖其某些功能以使用标识符跟踪“实际”名称,然后使用真实名称调用基本实现。

    class ToolBox(QtWidgets.QToolBox):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.names = []
            self.nameDict = {}
            self.setStyle(ProxyStyle(self))
    
        def updateNames(self):
            self.nameDict.clear()
            for i, realName in enumerate(self.names):
                fakeName = '__{}'.format(i)
                super().setItemText(i, fakeName)
                self.nameDict[fakeName] = realName
    
        def itemInserted(self, index):
            self.names.insert(index, super().itemText(index))
            self.updateNames()
    
        def itemRemoved(self, index):
            self.names.pop(index)
            self.updateNames()
    
        def setItemText(self, index, text):
            self.names[index] = text
            self.update()
    
        def itemText(self, index):
            return self.names[index]
    
    
    class ProxyStyle(QtWidgets.QProxyStyle):
        def __init__(self, toolBox):
            super().__init__(QtWidgets.QStyleFactory.create('fusion'))
            self.toolBox = toolBox
    
        def drawItemText(self, painter, rect, alignment, palette, enabled, text, role=QtGui.QPalette.NoRole):
            text = self.toolBox.nameDict.get(text, text)
            super().drawItemText(painter, rect, alignment, palette, enabled, text, role)
    

    要提升小部件,请在对象检查器中右键单击工具箱,选择“Promote to...”,然后在“Promoted class name”字段中输入“ToolBox”(我们的子类),输入名称存储类的文件(没有扩展名!),然后单击“添加”,最后单击“提升”。

    请注意,该类的文件甚至可以是主脚本,但在这种情况下,您必须为应用程序使用最后的 if __name__ == '__main__': 块,因为促销会将“标题”加载为导入。

    【讨论】:

    • 非常感谢您提供详细的答案。我设法通过删除侧面菜单上的边距来解决它。此外,对于省略的文本,我实际上减小了我在主“sidemenu”窗口上设置的字体大小,这为我解决了这个问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-16
    • 1970-01-01
    • 2018-02-10
    • 2015-12-28
    • 2013-06-17
    相关资源
    最近更新 更多