news 2026/6/10 19:21:05

基于PySide6实现DockWidget内部组件自动换行布局

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于PySide6实现DockWidget内部组件自动换行布局

DockWidget窗口大小改变时,内部的按钮能够自动重新排列,以最佳方式利用可用空间。具体表现为:

1. 当水平空间足够时,按钮排成一行

2. 当水平空间不足时,按钮自动换行

程序环境

Python 3.8.9

pyside6==6.1.3

pip install pyside6==6.1.3

设计结构图解

微信图片_2025-10-22_152148_073

实现效果

20251022_155729

demo代码获取

Gitee:dockwidget-demo

百度网盘:https://pan.baidu.com/s/1PRAjVGBtLQFZkWnZsJ2f2A?pwd=eiti

image

代码实现

以下是完整的实现代码:

import re

import sys

from PySide6.QtWidgets import QApplication

from ui_main_windowtest import *

class MainWindow(QMainWindow, Ui_MainWindow):

def __init__(self):

super().__init__()

self.setupUi(self)

self.row = 0 # 行

self.col = 0 # 列

self.buttons_per_row = 0 # 每行按钮数量

self.scrollArea.widget().installEventFilter(self)

# 获取布局参数

self.h_spacing = self.gridLayout_2.horizontalSpacing()

self.v_spacing = self.gridLayout_2.verticalSpacing()

self.margins = self.gridLayout_2.contentsMargins()

# 获取第一个按钮的参考尺寸

if self.gridLayout_2.count() > 0:

first_button = self.gridLayout_2.itemAt(0).widget()

self.button_width = first_button.sizeHint().width() + self.h_spacing

self.button_height = first_button.sizeHint().height() + self.v_spacing + 10 # 根据测试这里+10容差可以防止出现程序无限执行rearrangeButtons方法的情况

def eventFilter(self, obj, event):

"""监控ScrollArea内widget的resize事件"""

if event.type() == QEvent.Resize:

# 获取当前可用宽高

available_height = self.scrollArea.widget().size().height()

available_width = self.scrollArea.widget().size().width()

# 检查是否需要重新排列按钮

if available_height > (self.row + 1) * self.button_height and available_width > self.button_width:

self.rearrangeButtons()

elif available_width > (self.buttons_per_row + 1) * self.button_width and available_height > self.button_height:

self.rearrangeButtons()

return super().eventFilter(obj, event)

def rearrangeButtons(self):

"""重新排列按钮以适应新的窗口大小"""

# 计算新的每行按钮数量

available_width = self.scrollArea.widget().width() - self.margins.left() - self.margins.right()

new_buttons_per_row = max(1, available_width // self.button_width)

# 如果每行按钮数量没有变化,则不需要重新排列

if new_buttons_per_row != self.buttons_per_row:

self.buttons_per_row = new_buttons_per_row

else:

return

# 收集所有按钮

buttons = []

for i in range(self.gridLayout_2.count()):

item = self.gridLayout_2.itemAt(i)

if item.widget():

buttons.append(item.widget())

# 按按钮名称自然排序(1, 2, 3, ..., 10, 11),不排序每次重启程序顺序都会不一样

buttons.sort(key=lambda btn: [

int(text) if text.isdigit() else text.lower()

for text in re.split('([0-9]+)', btn.objectName())

])

# 清除当前布局

while self.gridLayout_2.count():

item = self.gridLayout_2.takeAt(0)

if item.widget():

item.widget().setParent(None)

# 重新排列按钮

for i, button in enumerate(buttons):

self.row = i // self.buttons_per_row

self.col = i % self.buttons_per_row

self.gridLayout_2.addWidget(button, self.row, self.col)

if __name__ == "__main__":

app = QApplication(sys.argv)

window = MainWindow()

window.show()

sys.exit(app.exec())

代码解析

1. 初始化布局参数

获取了布局的关键参数,这些参数用于准确计算可用空间和按钮尺寸:

self.h_spacing = self.gridLayout_2.horizontalSpacing()

self.v_spacing = self.gridLayout_2.verticalSpacing()

self.margins = self.gridLayout_2.contentsMargins()

2. 计算按钮尺寸

我们以scrollArea第一个Qwidget为参考,计算Qwidget的宽度和高度(所有Qwidget宽高必须统一):

ps:这里变量名写成了button,其实获取的是Qwidget的宽度和高度

first_button = self.gridLayout_2.itemAt(0).widget()

self.button_width = first_button.sizeHint().width() + self.h_spacing

self.button_height = first_button.sizeHint().height() + self.v_spacing + 10

注意这里加了10像素的容差,这是为了避免在某些边界情况下出现无限循环的问题。

3. 事件过滤器

通过eventFilter监控ScrollArea内widget的resize事件:

def eventFilter(self, obj, event):

if event.type() == QEvent.Resize:

# 获取当前可用宽高

available_height = self.scrollArea.widget().size().height()

available_width = self.scrollArea.widget().size().width()

# 检查是否需要重新排列

if available_height > (self.row + 1) * self.button_height and available_width > self.button_width:

self.rearrangeButtons()

elif available_width > (self.buttons_per_row + 1) * self.button_width and available_height > self.button_height:

self.rearrangeButtons()

return super().eventFilter(obj, event)

4. 重新排列按钮

rearrangeButtons方法是核心逻辑所在:

def rearrangeButtons(self):

# 计算新的每行按钮数量

available_width = self.scrollArea.widget().width() - self.margins.left() - self.margins.right()

new_buttons_per_row = max(1, available_width // self.button_width)

# 如果每行按钮数量没有变化,则不需要重新排列

if new_buttons_per_row != self.buttons_per_row:

self.buttons_per_row = new_buttons_per_row

else:

return

# 收集并排序按钮

buttons = []

for i in range(self.gridLayout_2.count()):

item = self.gridLayout_2.itemAt(i)

if item.widget():

buttons.append(item.widget())

# 使用正则表达式实现按钮名称的自然排序,可以通过命名的方式强制规定Qwidget组件顺序

buttons.sort(key=lambda btn: [

int(text) if text.isdigit() else text.lower()

for text in re.split('([0-9]+)', btn.objectName())

])

# 清除当前布局

while self.gridLayout_2.count():

item = self.gridLayout_2.takeAt(0)

if item.widget():

item.widget().setParent(None)

# 重新排列

for i, button in enumerate(buttons):

self.row = i // self.buttons_per_row

self.col = i % self.buttons_per_row

self.gridLayout_2.addWidget(button, self.row, self.col)

注意事项

按钮尺寸:DockWidget下的所有Qwidget应具有相同的尺寸,否则布局可能会不均匀

容差设置:代码中的+10像素容差是经验值,可能需要根据实际情况调整

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 13:58:43

通达信好公式个股突破

{}VAR1:SMA(AMOUNT,10,1)/1000000; VAR2:REF(VAR1,1); VAR3:MA(REF(CLOSE,1),5); 收盘:VAR1*CLOSE/VAR3*1/10,COLOR009900,LINETHICK0,POINTDOT; 开盘:VAR1*OPEN/VAR3*1/10,POINTDOT,COLOR009900,LINETHICK0; 最高:VAR1*HIGH/VAR3*1/10,POINTDOT,COLOR009900,LINETHICK0; 最低:…

作者头像 李华
网站建设 2026/6/10 15:40:11

使用国产的librestreaming实现RTMP直播

Fmpeg开发实战:从零基础到短视频上线》一书的“10.2.2 FFmpeg向网络推流”介绍了轻量级流媒体服务器MediaMTX,通过该工具可以测试RTSP/RTMP等流媒体协议的推拉流。可是在此之前,得先有一个推流工具向MediaMTX推送视频流,这样末端的…

作者头像 李华
网站建设 2026/6/10 5:31:14

10 个AI论文工具,助本科生轻松写完毕业论文!

10 个AI论文工具,助本科生轻松写完毕业论文! AI 工具如何让论文写作变得轻松高效 在当今信息爆炸的时代,高校学生尤其是本科生,面对毕业论文的撰写任务时常常感到无从下手。无论是选题、资料收集,还是撰写初稿、修改润…

作者头像 李华
网站建设 2026/6/10 15:55:12

qt5之实现一个视频播放器(亲测好用)

#ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow> #include <QMainWindow> #include <QMediaPlayer> #include <QVideoWidget> #include <QSlider> #include <QPushButton> <

作者头像 李华
网站建设 2026/6/10 10:29:00

【课程设计/毕业设计】基于springboot的在线考试系统的设计与实现考试评分管理,试卷管理【附源码、数据库、万字文档】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/6/10 15:57:44

【计算机毕业设计案例】基于springboot的云与糖蛋糕购物平台系统的设计与实现烘焙行业线上线下融合、个性化定制服务(程序+文档+讲解+定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华