一文解析 Python3 Pyqt5 布局

概述

  • 本文主要讲解Python3 PyQt5的布局,详细地介绍布局如何使用。

  • PyQt5中有哪些呢,可以利用Pycharm的自动补全找出来, 输入from PyQt5.QtWidgets import QLayout,等代码补全出来,显示的就算布局相关可以使用的类或者其基类(除绝对布局外), 善用代码提示。
    在这里插入图片描述
    主要有以下:

from PyQt5.QtWidgets import QHBoxLayout, QLayout, \
    QVBoxLayout, QFormLayout, QGridLayout, \
    QBoxLayout, QLayout, QStackedLayout, QGraphicsGridLayout,\
    QGraphicsAnchorLayout, QGraphicsLayout, QGraphicsLinearLayout, \
    QLayoutItem,\
    QGraphicsLayoutItem

按继承可以分成两部分, 一部分是继承自QLayout(QLayout继承自QLatoutItem), 一部分继承自QGraphicsLayout(而QGraphicsLayout继承自QGraphicsLayoutItem),关系图如下:

在这里插入图片描述

  • 本文主要内容:

    • 绝对布局
    • 盒子布局
      • 水平布局
      • 垂直布局
    • 网格布局
    • 表单布局
    • 嵌套布局/混合布局
    • 布局管理器QSplitter
  • 实例皆以此代码为基础实现:

import sys
from PyQt5.QtWidgets import QApplication, QWidget


class Window(QWidget):
    """
	窗体类
    """
    def __init__(self):
        super().__init__()
        self.setup_ui()

    def setup_ui(self):
    	"""
    	设置控件
    	"""
        pass


if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = Window()
    w.setWindowTitle('嵌套布局')
    w.show()
    sys.exit(app.exec_())

该段代码的执行效果是一个空面板,只有一个标题,如图:
在这里插入图片描述
下面开始讲解各个布局的使用。

绝对布局

  • 绝对布局可以直接定位每个空间的坐标。

  • 绝对布局在改变窗体大小之后不会自适应,所以看起来很乱,甚至改变个字体都会影响布局,新添加一个控件需要修改布局,那么所有控件都要进行修改,非常繁琐。

  • 绝对布局主要使用到以下两个方法:

    • move(x, y), 表示将控件移动至某个坐标。
    • setGeometry(x, y, w, h) 四个参数以此为横坐标,纵坐标,高度,宽度。
    • 这里的坐标是以屏幕左上角为起点计算的,即屏幕左上角的坐标为: (0, 0)。
  • 实例在窗体上摆放标签和按钮:

    import sys
    
    from PyQt5.QtWidgets import QApplication, QWidget
    from PyQt5.QtWidgets import QLabel, QPushButton
    from PyQt5.QtCore import QPoint
    
    
    class Window(QWidget):
        """
    
        """
        def __init__(self):
            super().__init__()
            self.setup_ui()
    
        def setup_ui(self):
            label1 = QLabel('标签1', self)
            label2 = QLabel('标签2', self)
            button = QPushButton('按钮', self)
    
            point = QPoint(10, 20)  # 定义一个点坐标
            label1.move(point)  # 移动到该坐标上
    
            label2.move(40, 50)  # 移动到坐标(40, 50)
    
            button.move(100, 30)  # 移动到坐标(100, 30)
    
            self.setGeometry(300, 300, 400, 300)
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        w = Window()
        w.setWindowTitle('绝对定位')
        w.show()
        sys.exit(app.exec_())
    
    

水平布局

定义在水平布局中的控件会按水平方式排列, 如图:
在这里插入图片描述
水平布局主要使用两个方法:

  • setLayout(layout) 设置窗体的布局方法
  • addWidget(widget, 10, Qt.AlignHCenter) widget为控件, 10为伸缩量, 最后一个参数为对齐方式。
  • 对齐方式就不一一举例了,通过代码提示和认识几个英文单词就能看出来了, 如图:
    在这里插入图片描述
  • 实例用户登录框:
import sys

from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout
from PyQt5.QtWidgets import QLabel, QLineEdit, QPushButton
from PyQt5.QtCore import Qt


class Window(QWidget):
    """
    窗体类
    """
    def __init__(self):
        super().__init__()
        self.setup_ui()

    def setup_ui(self):
        """
        设置控件
        :return:
        """

        usr_label = QLabel('账号')
        usr_input = QLineEdit('user')

        pwd_label = QLabel('密码')
        pwd_input = QLineEdit('pwd')

        login_btn = QPushButton('登录')

        layout = QHBoxLayout()  # 定义水平布局

        # 将空间加到布局中
        layout.addWidget(usr_label, 10, Qt.AlignTop)  # 垂直靠上对齐
        layout.addWidget(usr_input, 10, Qt.AlignBottom)  # 垂直靠下对齐

        layout.addWidget(pwd_label, 10, Qt.AlignRight)  # 右对齐
        layout.addWidget(pwd_input, 10, Qt.AlignLeft)  # 左对齐

        layout.addWidget(login_btn, 10, Qt.AlignHCenter)  # 居中对齐

        self.setLayout(layout)  # 设置当前widget的布局方式为水平布局
        self.setWindowTitle('水平布局!')


if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = Window()
    w.show()
    sys.exit(app.exec_())

垂直布局

垂直布局和水平布局使用方法一致,我们将刚刚的登录框代码做简单修改。
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout
layout = QVBoxLayout() # 定义垂直布局
边得到了垂直布局的效果图:
在这里插入图片描述
代码:

import sys

from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout
from PyQt5.QtWidgets import QLabel, QLineEdit, QPushButton
from PyQt5.QtCore import Qt


class Window(QWidget):
    """
    窗体类
    """
    def __init__(self):
        super().__init__()
        self.setup_ui()

    def setup_ui(self):
        """
        设置控件
        :return:
        """

        usr_label = QLabel('账号')
        usr_input = QLineEdit('user')

        pwd_label = QLabel('密码')
        pwd_input = QLineEdit('pwd')

        login_btn = QPushButton('登录')

        layout = QVBoxLayout()  # 定义垂直布局

        # 将空间加到布局中
        layout.addWidget(usr_label, 10, Qt.AlignTop)  # 垂直靠上对齐
        layout.addWidget(usr_input, 10, Qt.AlignBottom)  # 垂直靠下对齐

        layout.addWidget(pwd_label, 10, Qt.AlignRight)  # 右对齐
        layout.addWidget(pwd_input, 10, Qt.AlignLeft)  # 左对齐

        layout.addWidget(login_btn, 10, Qt.AlignHCenter)  # 居中对齐

        self.setLayout(layout)  # 设置当前widget的布局方式为layout
        self.setWindowTitle('垂直布局!')


if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = Window()
    w.show()
    sys.exit(app.exec_())

网格布局

网格布局主要用到两个方法:

方法 说明
addWidget(QWidget widget, int row, int col, int alignment = 0) 给网格布局添加控件。widget:要添加的控件。row:位置所在行,col:位置所在列,alignment:对齐方式
addWidget(QWidget widget, int fromRow, int fromColumn, int rowSpan, int columnSpan, int alignment) 当所添加的控件跨越多行或多列时,使用这个函数 fromRow:起始行 fromColumn:起始列 rowSpan:控件跨越的行 columnSpan:控件跨越的列

通过layout = QGridLayout() 定义网格布局, addWidet进行控件摆放。

import sys

from PyQt5.QtWidgets import QApplication, QWidget, QGridLayout
from PyQt5.QtWidgets import QLabel, QLineEdit, QPushButton
from PyQt5.QtCore import Qt


class Window(QWidget):
    """
    窗体类
    """
    def __init__(self):
        super().__init__()
        self.setup_ui()

    def setup_ui(self):
        """
        设置控件
        :return:
        """
        label = QLabel('标签')
        button = QPushButton('按钮')
        layout = QGridLayout()
        layout.addWidget(label, 1, 0, Qt.AlignCenter)
        layout.addWidget(button, 1, 1, Qt.AlignCenter)

        layout.addWidget(QPushButton('按钮2'), 3, 3, 5, 5, Qt.AlignCenter)

        for i in range(1, 10):
            layout.addWidget(QPushButton('测试{}'.format(str(i))), 2, i, Qt.AlignCenter)

        self.setLayout(layout)  # 设置布局
        self.setWindowTitle('网格布局!')


if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = Window()
    w.show()
    sys.exit(app.exec_())

在这里插入图片描述

表单布局

表单布局是以标签, 输入框的形式进行布局。
网格布局主要使用addRow方法:

  • addRow(self, QWidget, QWidget) 添加两个控件
  • addRow(self, QWidget, QLayout) 添加控件和布局
  • addRow(self, str, QWidget) 添加字符串和控件
  • addRow(self, str, QLayout) 添加字符串和布局
  • addRow(self, QWidget) 添加一个控件
  • addRow(self, QLayout) 添加一个布局

效果如图:
在这里插入图片描述

代码:

import sys

from PyQt5.QtWidgets import QApplication, QWidget, QFormLayout
from PyQt5.QtWidgets import QLabel, QLineEdit, QPushButton
from PyQt5.QtCore import Qt


class Window(QWidget):
    """
    窗体类
    """
    def __init__(self):
        super().__init__()
        self.setup_ui()

    def setup_ui(self):
        """
        设置控件
        :return:
        """
        layout = QFormLayout()

        self.setWindowTitle('网格布局!')

        usr_label = QLabel('账号')
        usr_input = QLineEdit('user')

        pwd_label = QLabel('密码')
        pwd_input = QLineEdit('pwd')

        layout.addRow(QPushButton('只添加了控件'))

        layout.addRow(usr_label, usr_input)
        layout.addRow(pwd_label, pwd_input)

        layout.addRow('验证码', QLineEdit('验证码'))
        layout.addRow('操作', QPushButton('提交'))

        child_layout = QFormLayout()
        child_layout.addRow('other', QLineEdit('token'))
        child_layout.addRow('other2', QLineEdit('token'))

        layout.addRow('附加信息', child_layout)  # 添加子布局, 子布局又是一个表单布局
        self.setLayout(layout)  # 设置布局


if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = Window()
    w.show()
    sys.exit(app.exec_())

嵌套布局/混合布局

在一个窗体中同时使用多种布局方式进行控件摆放。

混合布局也挺简单的, 控件可以添加到布局上, 控件可以设置布局。
父widget选取一种布局方式来布局, 然后创建一些子widget,在把子widget加到父widget中。

本例中选取QVBoxLayout垂直布局来作为基本布局, 在子布局中设置其他布局方式。

  import sys

from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QVBoxLayout, QFormLayout
from PyQt5.QtWidgets import QLabel, QLineEdit, QPushButton
from PyQt5.QtCore import Qt


class Window(QWidget):
    """
    窗体类
    """
    def __init__(self):
        super().__init__()
        self.setup_ui()

    def setup_ui(self):
        """
        设置控件
        :return:
        """
        self.setWindowTitle('混合布局')
        layout = QVBoxLayout()  # 垂直布局作为基布局
        self.setLayout(layout)

        form_layout = QFormLayout()  # 表单布局
        h_layout = QHBoxLayout()   # 垂直布局

        form_widget = QWidget()  # 创建一个子widget 并设置为表单布局
        form_widget.setLayout(form_layout)

        h_widget = QWidget()  # 创建一个子widget 并设置水平布局
        h_widget.setLayout(h_layout)

        # 表单布局中添加两个编辑框
        form_layout.addRow('账号:', QLineEdit())
        form_layout.addRow('密码:', QLineEdit())
		
		# 水平布局中添加两个按钮
        h_layout.addWidget(QPushButton('登录'))
        h_layout.addWidget(QPushButton('注册'))

        # 将子widget添加到基础布局中
        layout.addWidget(form_widget)
        layout.addWidget(h_widget)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = Window()
    w.show()
    sys.exit(app.exec_())

运行效果:

在这里插入图片描述

布局管理器QSplitter

QSplitter用于创建可以动态拖动控件。

方法 描述
addWidget() 将控件添加到QSplitter管理器的布局中
indexOf() 返回控件在QSplitter管理器中的索引
insertWidget() 根据索引将一个控件插入到QSplitter管理器中
setOrientation() 设置布局方法
Qt.Horizontal 水平方向
Qt.Vertical 垂直方向
setSizes() 设置控件的初始化大小
count() 返回小控件在QSplitter管理器中的数量

实例代码:

import sys

from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QVBoxLayout, QFormLayout, QSplitter
from PyQt5.QtWidgets import QPushButton,  QTextBrowser
from PyQt5.QtCore import Qt


class Window(QWidget):
    """
    窗体类
    """
    def __init__(self):
        super().__init__()
        self.setup_ui()

    def setup_ui(self):
        """
        设置控件
        :return:
        """
        layout = QVBoxLayout()
        self.setWindowTitle('QSplitter')
        self.setGeometry(300, 300, 800, 600)

        # 左上角对应一个表单布局并添加三个按钮
        top_left_widget = QWidget()
        top_left_layout = QFormLayout()
        top_left_widget.setLayout(top_left_layout)
        top_left_layout.addWidget(QPushButton('推荐'))
        top_left_layout.addWidget(QPushButton('电台'))
        top_left_layout.addWidget(QPushButton('歌单'))

        # 底部创建一个水平布局,添加三个按钮
        bottom_layout = QHBoxLayout()
        bottom_widget = QWidget()
        bottom_widget.setLayout(bottom_layout)
        bottom_layout.addWidget(QPushButton('快退'))
        bottom_layout.addWidget(QPushButton('暂停'))
        bottom_layout.addWidget(QPushButton('快进'))

        splitter = QSplitter(Qt.Horizontal)

        text_browser = QTextBrowser()

        # 第一个splitter分别把三个控件添加进去
        splitter.addWidget(top_left_widget)
        splitter.addWidget(text_browser)
        splitter.addWidget(bottom_widget)
        splitter.setSizes([100, 200])

        # 创建一个splitter2将第一个splitter和底部的空控件添加进来
        splitter2 = QSplitter(Qt.Vertical)
        splitter2.addWidget(splitter)
        splitter2.addWidget(bottom_widget)

        layout.addWidget(splitter2)  # splitter2添加到基础布局

        self.setLayout(layout)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = Window()
    w.show()
    sys.exit(app.exec_())

实现效果:
在这里插入图片描述
这个界面是可以拖动的。

QstackedLayout

栈式布局管理器管理的所有组件在垂直于屏幕的方向上,每次只显示一个组件界面。

实例:

import sys

from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel
from PyQt5.QtWidgets import QAbstractItemView, QStackedLayout, QListWidget


class Window(QWidget):
    """
    窗体类
    """

    def __init__(self):
        super().__init__()
        self.setup_ui()

    def setup_ui(self):
        """
        设置控件
        :return:
        """
        layout = QVBoxLayout()
        self.setLayout(layout)

        stacked_layout = QStackedLayout()

        list_widget = QListWidget()

        list_widget.setDragEnabled(True)
        list_widget.setDragDropMode(QAbstractItemView.InternalMove)

        layout.addWidget(list_widget)
        layout.addLayout(stacked_layout)

        stacked_layout.addWidget(QLabel('页面1的内容展示出来啦'))
        list_widget.addItem('页面1')

        stacked_layout.addWidget(QLabel('页面2的内容展示出来啦'))
        list_widget.addItem('页面2')

        # 槽函数绑定
        list_widget.currentRowChanged.connect(stacked_layout.setCurrentIndex)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = Window()
    w.show()
    sys.exit(app.exec_())

实现效果:
在这里插入图片描述

发布了65 篇原创文章 · 获赞 51 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/ClassmateLin/article/details/104465139