Python如何正确使用Qt Designer?

How to properly use Qt Designer together with Python?

我正在尝试学习使用 Qt Creator 和 qtpy 制作桌面应用程序,但我的结果看起来不像预期的那样。我在 Qt Designer 中创建了这个简单的东西(并期望结果看起来相似):

通过保存,我在 Python 项目目录的 'ui' 目录中得到了一个文件 mainwindow.ui。通过运行下面的脚本一次,我得到了一个mainwindow.py文件:

from qtpy import uic

uic.compileUiDir("ui")

接下来我运行我的主程序:

import sys
from qtpy import QtWidgets
from ui.mainwindow import Ui_MainWindow

app = QtWidgets.QApplication(sys.argv)

window = QtWidgets.QMainWindow()

ui_window = Ui_MainWindow()
ui_window.setupUi(window)

window.show()

sys.exit(app.exec_())

但是结果并不像预期的那样。所有的Widgets好像都太小了,内容都被砍掉了:

如何使结果看起来像 Qt Creator 中的那样?

我在虚拟环境中使用 Pycharm Community 2020.2 安装了以下 Python 个软件包: PyQt5 v 5.15.0 PyQt5-sip v 12.8.0 QtPy 1.9.0 版 我使用 Qt Creator 4.11.2

也许提供文件的详细信息会有所帮助

mainwindow.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>398</width>
    <height>673</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralWidget">
   <widget class="QPushButton" name="pushButton">
    <property name="geometry">
     <rect>
      <x>60</x>
      <y>30</y>
      <width>113</width>
      <height>32</height>
     </rect>
    </property>
    <property name="text">
     <string>PushButton</string>
    </property>
   </widget>
   <widget class="QRadioButton" name="radioButton">
    <property name="geometry">
     <rect>
      <x>270</x>
      <y>60</y>
      <width>100</width>
      <height>20</height>
     </rect>
    </property>
    <property name="text">
     <string>RadioButton</string>
    </property>
   </widget>
   <widget class="QCheckBox" name="checkBox">
    <property name="geometry">
     <rect>
      <x>50</x>
      <y>130</y>
      <width>87</width>
      <height>20</height>
     </rect>
    </property>
    <property name="text">
     <string>CheckBox</string>
    </property>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menuBar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>398</width>
     <height>22</height>
    </rect>
   </property>
  </widget>
  <widget class="QToolBar" name="mainToolBar">
   <attribute name="toolBarArea">
    <enum>TopToolBarArea</enum>
   </attribute>
   <attribute name="toolBarBreak">
    <bool>false</bool>
   </attribute>
  </widget>
  <widget class="QStatusBar" name="statusBar"/>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <resources/>
 <connections/>
</ui>

mainwindow.py:

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

# Form implementation generated from reading ui file 'ui\mainwindow.ui'
#
# Created by: PyQt5 UI code generator 5.15.0
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(398, 249)
        self.centralWidget = QtWidgets.QWidget(MainWindow)
        self.centralWidget.setObjectName("centralWidget")
        self.pushButton = QtWidgets.QPushButton(self.centralWidget)
        self.pushButton.setGeometry(QtCore.QRect(60, 30, 113, 32))
        self.pushButton.setObjectName("pushButton")
        self.radioButton = QtWidgets.QRadioButton(self.centralWidget)
        self.radioButton.setGeometry(QtCore.QRect(270, 60, 100, 20))
        self.radioButton.setObjectName("radioButton")
        self.checkBox = QtWidgets.QCheckBox(self.centralWidget)
        self.checkBox.setGeometry(QtCore.QRect(50, 130, 87, 20))
        self.checkBox.setObjectName("checkBox")
        MainWindow.setCentralWidget(self.centralWidget)
        self.menuBar = QtWidgets.QMenuBar(MainWindow)
        self.menuBar.setGeometry(QtCore.QRect(0, 0, 398, 21))
        self.menuBar.setObjectName("menuBar")
        MainWindow.setMenuBar(self.menuBar)
        self.mainToolBar = QtWidgets.QToolBar(MainWindow)
        self.mainToolBar.setObjectName("mainToolBar")
        MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.mainToolBar)
        self.statusBar = QtWidgets.QStatusBar(MainWindow)
        self.statusBar.setObjectName("statusBar")
        MainWindow.setStatusBar(self.statusBar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.pushButton.setText(_translate("MainWindow", "PushButton"))
        self.radioButton.setText(_translate("MainWindow", "RadioButton"))
        self.checkBox.setText(_translate("MainWindow", "CheckBox"))

您遇到的问题正是应该始终首选布局管理器的原因,而不是使用固定的几何图形。

您的特定问题的部分解决方案是在所有小部件上使用 adjustSize()

ui_window.checkBox.adjustSize()
ui_window.pushButton.adjustSize()
ui_window.radioButton.adjustSize()

通过这种方式,所有小部件都将调整它们的几何形状,确保它们能够显示所有内容。

但是,显然,这不是一个很好的解决方案,这不仅仅是因为您可能有几十个小部件。

固定几何图形的问题在于,您在计算机(甚至 Designer)中看到的内容在不同的计算机上几乎绝不会相同。这可能取决于很多因素,包括:

  • 系统配置
  • 默认字体和字体大小
  • 屏幕分辨率 DPI
  • 用户自定义

在您的情况下,不一致来自设计器如何使用 默认样式“绘制”小部件(请注意,您应该能够以不同样式预览您的 GUI,而不是“窗体”菜单)以及当您实际 运行 来自 python 的程序时实际发生的情况,使用 系统 默认样式。

使用布局管理器可以管理和优化可用 space,确保所有小部件都正确显示并尽可能多地使用 space。

固定几何形状有效的情况非常罕见,如果您确实需要它们,那只是因为您确实知道为什么以及如何处理它们。

对于剩下的 99.9% 的情况,实际解决方案是使用布局管理器。
右键单击界面的空白点,打开“布局...”子菜单,然后select其中一种可用布局。如果您需要将小部件放在更“特定”的位置,请考虑使用网格布局和 horizontal/vertical spacers(将它们从小部件框的顶部拖动)。