PyQt的布局管理器提供了一种用户友好且高效的方式来在GUI上排列图形组件或小部件。正确安排小部件将使您的GUI应用程序看起来更加精美和专业。学会有效地执行此操作是您使用Python和PyQt开发和运行GUI应用程序的基本技能。在本教程中,您将学习:使用PyQt的布局管理器有什么好处如何使用PyQt的布局管理器以编程方式在GUI上布置小部件如何为您的GUI应用程序选择正确的布局管理器有了这些知识和技能,您可以创建使用Python和PyQt的具有专业外观的GUI应用程序。在GUI上布置图形元素创建图形用户界面(GUI)应用程序时的一个常见问题是如何在窗体和窗口上一致地放置图形组件(按钮、菜单、工具栏、标签等)。这个过程称为图形用户界面布局(GUIlayout),这是创建图形用户界面应用程序的重要步骤。以前,如果您在窗口上布置图形组件或小部件,您可以执行以下操作之一:确定并手动设置窗口上每个小部件的静态大小和位置。动态计算和设置每个小部件的大小和位置。第一种方法相当简单,但至少有以下缺点:您的窗口不能调整大小,这可能会导致在不同屏幕分辨率下显示它们时出现问题。您的标签可能无法正确支持本地化,因为给定文本的长度因语言而异。您的小部件在不同平台上的显示方式会有所不同,因此很难编写出看起来不错的多平台应用程序。第二种方法更灵活。但是,它也有缺点:您必须进行大量手动计算才能确定每个小部件的正确大小和位置。您必须进行一些额外的计算才能正确响应窗口大小调整。每当您修改窗口布局时,都必须重做所有计算。尽管您仍然可以使用这两种方法中的任何一种来布局GUI,但大多数时候您可能希望使用第三种更方便的方法,该方法由最先进的GUI框架或工具包实现:布局管理器管理人员。注意:在某些GUI框架(例如Tkinter)中,布局管理器也称为几何管理器。布局管理器根据您的特定需要自动在GUI上排列小部件。它避免了第一种方法的兼容性缺点和第二种方法的复杂计算。在以下部分中,您将了解PyQt的内置布局管理器以及如何使用它们有效地布置GUI应用程序的图形组件。各种PyQt布局形式在PyQt中,小部件是图形组件,用作GUI应用程序的构建块。当您将一堆小部件放在窗口上以创建GUI时,您需要给它们一些顺序。您需要设置小部件在窗口上的大小和位置,并且需要定义它们在用户调整底层窗口大小时的行为。注意:PyQt5的官方文档中有一些不完整的部分。要解决此问题,您可以查看PyQt4文档、QtforPython文档或原始Qt文档。要在PyQt窗口或表单上排列小部件,可以使用以下技术:在小部件上使用.resize()和.move()来提供绝对大小和位置。重新实现.resizeEvent()并动态计算小部件的大小和位置。使用布局管理器,让他们为您完成所有计算和艰苦的工作。这些技术通常对应于上一节介绍的三种不同的GUI布局方法。同样,动态计算大小和位置可能是一个好方法,但大多数时候,使用布局管理器更好。在PyQt中,布局管理器是提供自动管理布局中小部件的大小、位置和调整大小行为所需功能的类。使用布局管理器,您可以在任何父部件、容器、部件内自动安排子部件。使用布局管理器将确保您充分利用GUI上的可用空间,并确保当用户调整窗口大小时,应用程序仍然可用。当布局管理器充当小部件和其他布局的容器时,要将小部件添加到布局管理器,请在当前布局上调用.addWidget()。要将布局添加到另一个布局,请在当前布局上调用.addLayout()。您将在“嵌套布局以构建复杂GUI”部分中了解有关嵌套布局的更多信息。将所有必需的小部件添加到布局管理器后,您可以使用.setLayout()在给定的小部件上设置布局管理器。您可以在QWidget的任何子类上设置布局管理器,包括Window或Form。注意:QMainWindow是一个PyQt类,可用于创建主窗口样式的应用程序。这个类有它自己的内置布局管理器。因此,如果您使用QMainWindow,通常不需要在主窗口对象上设置布局管理器。布局中的所有小部件都会自动设置为安装布局的小部件的子项,而不是布局本身。这是因为小部件只能将其他小部件(不是布局)作为其父级。PyQt的布局管理器提供了一些很酷的功能,可以让您在创建美观的GUI应用程序时更轻松:无需任何计算即可处理小部件的大小和定位当用户调整底层窗口大小时处理小窗口调整小部件的大小和重新定位调整标签大小以更好地支持国际化为多平台应用程序提供本机窗口布局使用布局管理器还将大大提高您的工作效率并在长期运行中提高代码的可维护性。PyQt提供了四个通用布局管理器类:QHBoxLayout将小部件排列在水平框中。QVBoxLayout在垂直框中排列小部件。QGridLayout在网格中排列小部件。QFormLayout将小部件排列成两列。在接下来的几节中,您将了解如何使用这些通用布局管理器的基础知识。当使用PyQt使用通用布局管理器创建GUI应用程序时,您通常使用在上一节末尾看到的四种通用布局中的一个或多个来在窗口和窗体上布置小部件。在接下来的几节中,您将学习如何在一些示例的帮助下创建和使用四个通用布局管理器。构建水平布局:QHBoxLayoutBox布局管理器从父布局或widget中获取的空间被划分为多个boxes或cells,然后让布局中的每个widget填充一个box。QHBoxLayout是PyQt中可用的两种框布局之一。这个布局管理器允许您水平排列小部件,一个接一个。小部件从左到右添加到布局中。这意味着您在代码中首先添加的小部件将是布局中最左边的小部件。要将小部件添加到QHBoxLayout对象,请在布局对象上调用.addWidget(widget,stretch,alignment)。此方法接受一个必需参数和两个可选参数:widget是一个必需参数,用于保存要添加到布局中的特定小部件。Stretch是一个可选参数,它包含一个整数,表示要应用于小部件的拉伸因子。调整窗口大小时,具有较高拉伸因子的小部件将增长得更多。默认为0,这意味着没有分配小部件拉伸因子。alignment是一个可选参数,包含水平和垂直标志。您可以组合这些标志以在其包含的单元格内生成小部件所需的对齐方式。默认为0,这意味着小部件将填充整个单元格。下面是一个小应用程序,展示了如何使用QHBoxLayout创建水平布局。在此示例中,您将使用QPushButton对象根据将小部件添加到代码中的顺序更好地可视化每个小部件在布局中的位置:importsysfromPyQt5.QtWidgetsimport(QApplication,QHBoxLayout,QPushButton,QWidget,)classWindow(QWidget):def__init__(self):super().__init__()self.setWindowTitle("QHBoxLayoutExample")#CreateaQHBoxLayoutinstancelayout=QHBoxLayout()#Addwidgetstothelayoutlayout.addWidget(QPushButton("最左边"))layout.addWidget(QPushButton("Center"),1)layout.addWidget(QPushButton("Right-Most"),2)#Setthelayoutontheapplication'swindowsself.setLayout(layout)print(self.children())if__name__=="__main__":app=QApplication(sys.argv)window=Window()window.show()sys.exit(app.exec_())在第15行,创建了一个名为layout的QHBoxLayout对象。在第17到19行,使用.addWidget()将三个按钮添加到布局中。请注意,您分别将1和2传递给“中心”和“最右边”按钮中的拉伸参数。在第21行,使用.setLayout()将布局设??置为窗口的顶级布局。如果运行该应用程序,您将在屏幕上看到以下窗口:该窗口包含三个水平排列的按钮。请注意,“最左边”按钮对应于您在代码中添加的第一个按钮。因此按钮的显示顺序与您在代码中添加的顺序相同(从左到右)(从上到下)。“居中”和“最右边”按钮具有不同的拉伸系数,因此它们会在调整窗口大小时按比例缩放。此外,布局中的所有按钮和布局本身都设置为Window的子项。这是由布局对象自动完成的,它在每个小部件上内部调用.setParent()。第17行对print()的调用会将Window的子项列表打印到您的终端以演示此行为。构建垂直布局:QVBoxLayoutQVBoxLayout垂直排列小部件,一个在另一个下面。您可以使用此类创建垂直布局并从上到下排列小部件。由于QVBoxLayout是另一种盒子布局,其.addWidget()方法与QHBoxLayout中的工作方式相同。这是一个PyQt应用程序,展示了如何创建和使用QVBoxLayout对象在GUI中创建垂直排列的小部件:().__init__()self.setWindowTitle("QVBoxLayoutExample")self.resize(270,110)#CreateaQVBoxLayoutinstancelayout=QVBoxLayout()#Addwidgetstothelayoutlayout.addWidget(QPushButton("Top"))layout.addWidget(QPushButton("Center"))布局.addWidget(QPushButton("Bottom"))#Setthelayoutontheapplication'swindowsself.setLayout(layout)if__name__=="__main__":app=QApplication(sys.argv)window=Window()window.show()sys.exit(app.exec_())在第16行,您创建了一个QVBoxLayout实例。在第18到20行,向布局添加三个按钮。最后,将布局设置为窗口的顶层布局。如果您运行该应用程序,将出现以下窗口:您的窗口显示三个垂直排列的按钮,一个在另一个下面。这些按钮的显示顺序(从上到下)与您在代码中添加它们的顺序(从上到下)相同。在网格中排列小部件:QGridLayout您可以使用QGridLayout将小部件排列在由行和列组成的网格中。每个小部件在网格中都有一个相对位置。要定义小部件或单元格在网格中的位置,请使用表(行、列)坐标对。这些坐标应该是从零开始的整数。QGridLayout获取其父级的可用空间,将其划分为行和列,并将每个小部件放置在其自己的单元格或框中。QGridLayout根据小部件的数量及其坐标自动计算最终布局将包含多少行和列。如果您不向给定的单元格添加小部件,QGridLayout将使该单元格为空。要将小部件添加到网格布局,请在布局上调用.addWidget()。此方法有两种不同的重载实现:addWidget(widget,row,column,alignment)将小部件添加到位于(row,column)的单元格中。addWidget(widget,fromRow,fromColumn,rowSpan,columnSpan,alignment)将小部件添加到单元格,跨越多行、多列或两者。第一个实现采用以下参数:widget是一个必需参数,它包含您需要添加到布局中的特定小部件。row是一个必需的参数,它包含一个表示网格中行坐标的整数。column是一个必需的参数,它包含一个表示网格中列坐标的整数。alignment是一个可选参数,用于保存小部件在其包含单元格中的对齐方式。默认为0,这意味着小部件将填充整个单元格。这是一个如何使用QGridLayout创建小部件网格式的示例:importsysfromPyQt5.QtWidgetsimport(QApplication,QGridLayout,QPushButton,QWidget,)classWindow(QWidget):def__init__(self):super().__init__()self.setWindowTitle("QGridLayoutExample")#CreateaQGridLayoutinstancelayout=QGridLayout()#Addwidgetstothelayoutlayout.addWidget(QPushButton("Buttonat(0,0)"),0,0)layout.addWidget(QPushButton("Buttonat(0,1)"),0,1)layout.addWidget(QPushButton("Buttonat(0,2)"),0,2)layout.addWidget(QPushButton("Buttonat(1,0)"),1,0)layout.addWidget(QPushButton("Buttonat(1,1)"),1,1)layout.addWidget(QPushButton("Buttonat(1,2)"),1,2)layout.addWidget(QPushButton("Buttonat(2,0)"),2,0)layout.addWidget(QPushButton("Buttonat(2,1)"),2,1)layout.addWidget(QPushButton("Buttonat(2,2)"),2,2)#Setthelayoutontheapplication'swindowsself.setLayout(layout)if__name__=="__main__":app=QApplication(sys.argv)window=Window()window.show()sys.exit(app.exec_())在第15行,创建了QGridLayout对象然后,在第17到25行,使用.addWidget()将小部件添加到布局中。要查看未分配小部件的网格布局如何管理单元格,请注释掉这些行中的一行或多行,然后再次运行该应用程序。如果您从命令行运行此代码,您将得到一个如下所示的窗口:QGridLayout对象中的每个小部件占据一个单元格,该单元格由您在.addWidget()中提供的一对坐标定义。每个按钮上的文本反映了这些坐标。坐标从零开始,因此第一个单元格位于(0,0)。在.addWidget()的第二个实现中,小部件和对齐参数保持不变,您还有四个其他参数可用于将小部件放置在多行或多列中:开始。fromColumn分配一个整数,表示小部件将在其中开始的列。rowSpan分配一个整数,表示小部件将在网格中占据的行数。columnSpan分配一个整数,表示小部件将在网格中占据的列数。这是一个显示.addWidget()变体如何工作的应用程序:")#CreateaQGridLayoutinstancelayout=QGridLayout()#Addwidgetstothelayoutlayout.addWidget(QPushButton("Buttonat(0,0)"),0,0)layout.addWidget(QPushButton("Buttonat(0,1)"),0,1)layout.addWidget(QPushButton("ButtonSpanstwoCols"),1,0,1,2)#Setthelayoutontheapplication'swindowself.setLayout(layout)if__name__=="__main__":app=QApplication(sys.argv)window=Window()window.show()sys.exit(app.exec_())在第19行,使用.addWidget()的第二个实现来添加一个在网格中占据两列的按钮。该按钮从第二行(fromRow=1)和第一列(fromColumn=0)开始。最后,按钮占用一行(rowSpan=1)和两列(columnSpan=2)。如果你运行这个应用程序,你会在屏幕上看到下面的窗口:在这个布局中,你可以让一个小部件占据多个单元格,就像使用一个“跨越两列”的按钮一样。在下一部分中,我们将看到:如何快速创建表单嵌套布局以构建复杂的GUI使用多页面布局和小部件布置应用程序的主窗口布置应用程序的对话框管理PyQt布局中的输入框
