python pyside2 Widget容器(QWidget )

介绍

在 PySide2(Qt for Python)GUI 开发中,QWidget 是所有可视化控件的基类(如 QFrame、QPushButton、QLineEdit 均继承自 QWidget),同时也是最基础的 容器控件—— 用于承载子控件、组织界面结构。本文将从核心特性、基础操作、布局结合、自定义扩展四个维度,系统讲解 QWidget 的使用方法,为复杂界面开发打下基础。

提示: 一般很少使用

作为 “控件基类” 的作用

所有 PySide2 可视化控件(除少数特殊组件外)均直接或间接继承自 QWidget,这意味着 QWidget 的核心属性与方法(如大小、位置、显示 / 隐藏)会被所有控件继承。例如:

  • QPushButton(按钮)继承自 QAbstractButton,而 QAbstractButton 继承自 QWidget;

  • QFrame(框架)直接继承自 QWidget,QLineEdit 则继承自 QFrame。

因此,掌握 QWidget 是理解其他控件的基础,其核心能力可概括为:

核心能力 说明 继承后控件的表现
几何属性控制(位置 / 大小) 控制控件在父容器中的坐标、宽度、高度 所有控件均可通过 setGeometry() 调整位置大小
显示状态控制 控制控件的显示、隐藏、启用 / 禁用 所有控件均可调用 show()/hide()/setEnabled()
事件处理 响应鼠标点击、键盘输入、窗口 resize 等事件 所有控件均可重写 mousePressEvent() 等事件方法
样式定制 通过 StyleSheet 调整外观 所有控件均可通过 setStyleSheet() 美化

作为 “容器控件” 的作用

当 QWidget 不承担具体交互功能(如按钮点击、文本输入)时,其主要作用是承载子控件并组织界面结构,常见应用场景:

  • 顶层窗口:作为应用程序的主窗口(如 QMainWindow 的中心部件,或独立的弹窗窗口);

  • 子容器:包裹一组相关控件(如 “登录表单” 的账号、密码输入框,用 QWidget 作为父容器统一管理);

  • 自定义控件基类:基于 QWidget 扩展带特定功能的自定义控件(如自定义仪表盘、进度条)。

基础用法

创建顶层窗口(独立窗口)

QWidget 可直接作为顶层窗口使用,需设置窗口标题、大小等属性,调用 show() 显示:

from PySide2.QtWidgets import QApplication, QWidget

import sys

app = QApplication(sys.argv)  # 初始化应用(所有 PySide2 程序必须有一个 QApplication)

\# 1. 创建 QWidget 作为顶层窗口

window = QWidget()

window.setWindowTitle("QWidget 顶层窗口示例")  # 设置窗口标题

window.resize(400, 300)  # 设置窗口初始大小(宽度 400px,高度 300px)

window.move(100, 100)    # 设置窗口在屏幕上的初始位置(x=100px,y=100px,左上角为原点)

\# 2. 显示窗口

window.show()

sys.exit(app.exec\_())  # 启动应用事件循环,等待用户操作

创建子控件(依附于父容器)

QWidget 作为子控件时,需指定父容器(通过构造函数参数或 setParent() 方法),其位置会相对于父容器计算:

from PySide2.QtWidgets import QLabel

\# 1. 创建顶层窗口(父容器)

parent\_window = QWidget()

parent\_window.setWindowTitle("QWidget 子控件示例")

parent\_window.resize(400, 300)

\# 2. 创建 QWidget 作为子容器(父容器为 parent\_window)

child\_widget = QWidget(parent\_window)

child\_widget.setGeometry(50, 50, 300, 200)  # 相对于父容器的位置与大小(x=50, y=50, w=300, h=200)

child\_widget.setStyleSheet("background-color: #F0F8FF;")  # 设置背景色,便于区分

\# 3. 在子容器中添加标签(子控件的子控件)

label = QLabel("这是子容器中的标签", child\_widget)

label.move(20, 20)  # 相对于子容器 child\_widget 的位置

parent\_window.show()

sys.exit(app.exec\_())

关键方法说明:

方法 功能描述 示例代码
resize(width, height) 设置控件大小(宽度、高度) window.resize(400, 300)
move(x, y) 设置控件位置(相对于父容器左上角的 x、y 坐标) child_widget.move(50, 50)
setGeometry(x, y, width, height) 同时设置位置与大小(合并 move + resize) child_widget.setGeometry(50,50,300,200)
size() 获取控件当前大小(返回 QSize 对象,含 width()/height() 方法) size = window.size() → width = size.width()
pos() 获取控件当前位置(返回 QPoint 对象,含 x()/y() 方法) pos = child_widget.pos() → x = pos.x()

显示与状态控制

QWidget 提供多种方法控制显示状态与交互能力,满足不同场景需求:

\# 1. 显示与隐藏

window.show()    # 显示控件(若为顶层窗口,显示窗口)

window.hide()    # 隐藏控件(若为顶层窗口,隐藏窗口)

window.isVisible()  # 判断控件是否可见(返回 True/False)

\# 2. 启用与禁用(禁用后控件不可交互,外观变灰)

button = QPushButton("点击按钮", window)

button.setGeometry(20, 20, 100, 30)

button.setEnabled(False)  # 禁用按钮(无法点击)

button.isEnabled()        # 判断控件是否启用(返回 True/False)

\# 3. 置顶窗口(仅顶层窗口生效)

window.setWindowFlags(window.windowFlags() | Qt.WindowStaysOnTopHint)  # 设置窗口置顶

window.setWindowFlags(window.windowFlags() & \~Qt.WindowStaysOnTopHint) # 取消置顶

\# 4. 全屏显示(仅顶层窗口生效)

window.showFullScreen()  # 全屏显示

window.showNormal()      # 恢复正常大小

与布局结合:自适应排版

QWidget 作为容器时,若手动通过 setGeometry() 定位子控件,会导致窗口缩放时子控件位置错乱。因此,必须结合布局管理实现自适应排版,核心步骤:

  1. 创建 QWidget 作为父容器;

  2. 创建布局(如 QVBoxLayout、QHBoxLayout);

  3. 将子控件加入布局;

  4. 通过 setLayout() 将布局绑定到 QWidget。

实战示例:QWidget + QVBoxLayout 实现自适应表单

from PySide2.QtWidgets import QVBoxLayout, QLineEdit, QPushButton, QLabel

\# 1. 创建父容器 QWidget(顶层窗口)

form\_window = QWidget()

form\_window.setWindowTitle("QWidget + 布局 自适应表单")

form\_window.resize(350, 250)

\# 2. 创建垂直布局

v\_layout = QVBoxLayout()

v\_layout.setSpacing(15)  # 子控件间间距 15px

v\_layout.setContentsMargins(20, 20, 20, 20)  # 布局内边距(上下左右各 20px)

\# 3. 向布局中添加子控件

title\_label = QLabel("用户登录")

title\_label.setStyleSheet("font-size: 18px; font-weight: bold; text-align: center;")

account\_edit = QLineEdit()

account\_edit.setPlaceholderText("请输入账号")

account\_edit.setStyleSheet("padding: 8px; border: 1px solid #DDDDDD; border-radius: 4px;")

pwd\_edit = QLineEdit()

pwd\_edit.setEchoMode(QLineEdit.Password)

pwd\_edit.setPlaceholderText("请输入密码")

pwd\_edit.setStyleSheet("padding: 8px; border: 1px solid #DDDDDD; border-radius: 4px;")

login\_btn = QPushButton("登录")

login\_btn.setStyleSheet("""

    QPushButton {

        background-color: #2196F3;

        color: white;

        border: none;

        border-radius: 4px;

        padding: 10px;

        font-size: 14px;

    }

    QPushButton:hover {

        background-color: #1976D2;

    }

""")

\# 4. 将控件加入布局(顺序决定排列顺序:上→下)

v\_layout.addWidget(title\_label)

v\_layout.addWidget(account\_edit)

v\_layout.addWidget(pwd\_edit)

\# 加入弹性空白,将按钮推到下方(窗口缩放时按钮位置固定在底部)

v\_layout.addStretch(1)

v\_layout.addWidget(login\_btn)

\# 5. 将布局绑定到父容器 QWidget

form\_window.setLayout(v\_layout)

form\_window.show()

sys.exit(app.exec\_())

效果说明:

  • 窗口缩放时,账号 / 密码输入框宽度自动跟随窗口变化(因布局自适应);

  • v_layout.addStretch(1) 加入的弹性空白,确保登录按钮始终位于表单底部;

  • 无需手动调整子控件位置,布局自动维护控件间距与对齐方式。

事件处理

QWidget 作为基类,支持重写大量事件方法(如鼠标点击、键盘输入、窗口大小变化),实现自定义交互逻辑。事件处理的核心是重写 QWidget 的内置事件方法,常见事件如下:

鼠标事件(点击、移动、释放)

class CustomWidget(QWidget):

    def \_\_init\_\_(self, parent=None):

        super().\_\_init\_\_(parent)

        self.setWindowTitle("自定义鼠标事件")

        self.resize(400, 300)

        self.click\_pos = None  # 记录鼠标点击位置

    \# 重写鼠标按下事件(左键点击时触发)

    def mousePressEvent(self, event):

        if event.button() == Qt.LeftButton:  # 判断是否为左键点击

            self.click\_pos = event.pos()  # 获取鼠标相对于当前控件的位置

            print(f"鼠标左键点击:x={self.click\_pos.x()}, y={self.click\_pos.y()}")

    \# 重写鼠标移动事件(鼠标在控件上移动时触发)

    def mouseMoveEvent(self, event):

        if self.click\_pos is not None:  # 仅当左键按下时才响应移动

            current\_pos = event.pos()

            dx = current\_pos.x() - self.click\_pos.x()

            dy = current\_pos.y() - self.click\_pos.y()

            \# 移动窗口(若为顶层窗口)

            self.move(self.x() + dx, self.y() + dy)

    \# 重写鼠标释放事件(鼠标按键释放时触发)

    def mouseReleaseEvent(self, event):

        if event.button() == Qt.LeftButton:

            self.click\_pos = None  # 重置点击位置

            print("鼠标左键释放")

\# 使用自定义控件

app = QApplication(sys.argv)

custom\_window = CustomWidget()

custom\_window.show()

sys.exit(app.exec\_())

键盘事件(按键按下、释放)

class KeyEventWidget(QWidget):

    def \_\_init\_\_(self, parent=None):

        super().\_\_init\_\_(parent)

        self.setWindowTitle("自定义键盘事件")

        self.resize(400, 300)

        self.label = QLabel("按下键盘查看输出...", self)

        self.label.setGeometry(20, 20, 360, 30)

    \# 重写键盘按下事件

    def keyPressEvent(self, event):

        \# 获取按下的键(如 Qt.Key\_A、Qt.Key\_Escape)

        key = event.key()

        \# 获取按键文本(如 "A"、"Escape")

        key\_text = event.text() if event.text() else event.keyToString()

        self.label.setText(f"按下键盘:{key\_text}(键值:{key})")

        

        \# 特殊键处理(如 Esc 键关闭窗口)

        if key == Qt.Key\_Escape:

            self.close()

app = QApplication(sys.argv)

key\_window = KeyEventWidget()

key\_window.show()

sys.exit(app.exec\_())

窗口大小变化事件

class ResizeWidget(QWidget):

    def \_\_init\_\_(self, parent=None):

        super().\_\_init\_\_(parent)

        self.setWindowTitle("窗口大小变化事件")

        self.resize(400, 300)

    \# 重写窗口大小变化事件

    def resizeEvent(self, event):

        \# 获取变化后的窗口大小

        new\_size = event.size()

        print(f"窗口大小变化:宽={new\_size.width()}, 高={new\_size.height()}")

        \# 可在此处调整子控件大小(若未使用布局)

        \# 例如:让标签宽度跟随窗口宽度变化

        if hasattr(self, "label"):

            self.label.setGeometry(20, 20, new\_size.width() - 40, 30)

    \# 初始化时添加标签

    def showEvent(self, event):

        self.label = QLabel("窗口大小变化时我会自适应宽度", self)

        self.label.setGeometry(20, 20, self.width() - 40, 30)

app = QApplication(sys.argv)

resize\_window = ResizeWidget()

resize\_window.show()

sys.exit(app.exec\_())

原文出处:/show_1GW1rHsEnUFz.html