尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

07. 自定义组件

07. 自定义组件
📅 发布时间:2026/6/19 6:11:59

一、在单独文件中自定义组件

  我们可以在终端中使用 pip 安装 PySide6 模块。默认是从国外的主站上下载,因此,我们可能会遇到网络不好的情况导致下载失败。我们可以在 pip 指令后通过 -i 指定国内镜像源下载。

pip install pyside6 -i https://mirrors.aliyun.com/pypi/simple

  国内常用的 pip 下载源列表:

  • 阿里云 https://mirrors.aliyun.com/pypi/simple
  • 中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple
  • 清华大学 https://pypi.tuna.tsinghua.edu.cn/simple
  • 中国科学技术大学 http://pypi.mirrors.ustc.edu.cn/simple

  虽然 QML 中提供了多个样式可供使用,但是用户有时还是想实现自定义的外观。这里,我们新建一个 MyButton.qml 文件,用来存放自定义的组件。

import QtQuickRectangle {id: containerRectIdwidth: buttonTextId.implicitWidth + 60height: buttonTextId.implicitHeight + 20color: "#99CCFF"// 为内部的Text元素提供一个别名属性,方便在外部设置按钮的文本property alias buttonText: buttonTextId.textsignal buttonClicked()                                                      // 自定义一个信号border {width: 1color: "#666666"}Text {id: buttonTextIdanchors.centerIn: parenttext: "按钮"font.pointSize: 16color: "#FF6666"}MouseArea {id: mouseAreaIdanchors.fill: parentonClicked: {containerRectId.buttonClicked()                                     // 触发信号}}
}

  在 QML 中,我们无法使用自定义组件内部元素的属性,因此,我们需要使用 alias 关键字给内部元素的属性起一个别名,方便在外部设置该内部元素的属性值。

  我们新建一个 template.qml 文件,在该文件中调用自定义的 QML 组件。

import QtQuick.Window
import QtQuick.Layouts// Window控件表示一个顶级窗口
// 在QML中,元素是通过大括号{}内的属性来配置的。
Window {width: 800                                                                  // 窗口的宽度height: 600                                                                 // 窗口的高度visible: true                                                               // 显示窗口color: "lightgray"                                                          // 窗口的背景颜色Text {id: textIdanchors.centerIn: parentfont.pointSize: 32color: "#FF6666"}Column {MyButton {buttonText: "按钮1"onButtonClicked: {textId.text = "按钮1被点击了"}}MyButton {buttonText: "按钮2"onButtonClicked: {textId.text = "按钮2被点击了"}}}
}

  这里,我们将 template.qml 文件和 MyButton.qml 文件放置到同一级目录下。然后,我们可以在 template.qml 文件中直接用存放自定义组件的文件名创建自定义组件。

  自定义组件的名称一定要与存放自定义组件的文件名首字母一致,否则会报如下错误:

file:///E:/Software/Python/PySide6/Template/template.qml:13:9: MyButton is not a type
file:///E:/Software/Python/PySide6/Template/template.qml: File name case mismatch   

  自定义组件的存放文件的首字母一定要大写,否则会报如下错误:

file:///E:/Software/Python/PySide6/Template/template.qml:22:9: Cannot assign to non-existent property "myButton"

  我们新建一个 template.py 文件,用来加载 template.qml 文件。

import sysfrom PySide6.QtWidgets import QApplication
from PySide6.QtQml import QQmlApplicationEngineif __name__ == "__main__":app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例engine = QQmlApplicationEngine()                                            # 2.创建QML引擎对象engine.load("template.qml")                                                 # 3.加载QML文件sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束

这里自定义组件的 QML 文件名的首字母一定要大写。

自定义的组件名与 QML 文件名一致。

组件实例的 id 和组成组件的顶层 Item 的 id 是各自独立的。

二、使用component自定义组件

  我们修改 template.qml 文件的内容,使用 component 自定义一个组件。

import QtQuick.Window// Window控件表示一个顶级窗口
// 在QML中,元素是通过大括号{}内的属性来配置的。
Window {width: 800                                                                  // 窗口的宽度height: 600                                                                 // 窗口的高度visible: true                                                               // 显示窗口color: "lightgray"// MyButton为自定义的组件名component MyButton: Rectangle {id: containerRectIdwidth: buttonTextId.implicitWidth + 60height: buttonTextId.implicitHeight + 20color: "#99CCFF"// 为内部的Text元素提供一个别名属性,方便在外部设置按钮的文本property alias buttonText: buttonTextId.textsignal buttonClicked()                                                  // 自定义一个信号border {color: "#666666"width: 1}Text {id: buttonTextIdtext: "按钮"font.pointSize: 16color: "#FF6666"anchors.centerIn: parent}MouseArea {id: mouseAreaIdanchors.fill: parentonClicked: {containerRectId.buttonClicked()                                 // 触发信号}}}Text {id: textIdanchors.centerIn: parentfont.pointSize: 32color: "#FF6666"}Row {spacing: 20MyButton {buttonText: "按钮1"onButtonClicked: {textId.text = "按钮1被点击了"}}MyButton {buttonText: "按钮2"onButtonClicked: {textId.text = "按钮2被点击了"}}}
}

三、Component组件

  Component 是由 Qt 框架或开发者封装好的、只暴露了必要接口的 QML 类型,可以重复利用。一个 QML 组件就像一个黑盒子,它通过属性、信号、函数和外部世界交互。

  Component 有两个信号:completed() 信号会在 对象实例化后 发出的信号,destruction() 信号会在 在对象开始销毁 时发出x信号。

  修改 template.qml 文件的内容。

import QtQuick.Window// Window控件表示一个顶级窗口
// 在QML中,元素是通过大括号{}内的属性来配置的。
Window {width: 800                                                                  // 窗口的宽度height: 600                                                                 // 窗口的高度visible: true                                                               // 显示窗口color: "lightgray"// 对象实例化后发出的信号。一旦建立了完整的 QML 环境,它就可用于在启动时执行脚本代码。Component.onCompleted: {console.log("Component.onCompleted")console.log("width: " + width, ", height: " + height, ", color: " + color)}// 在对象开始销毁时发出信号Component.onDestruction: {console.log("Component.onDestruction")}
}

  我们还可以自定义一个 Component。Component 只能包含一个顶层 Item,而且在这个顶层 Item 之外不能定义除了 id 属性以外的任何数据。而在顶层 Item 之内,则可以包含更多的子元素来协同工作,最终形成一个具有特定功能的组件。

import QtQuick.Window// Window控件表示一个顶级窗口
// 在QML中,元素是通过大括号{}内的属性来配置的。
Window {width: 800                                                                  // 窗口的宽度height: 600                                                                 // 窗口的高度visible: true                                                               // 显示窗口color: "lightgray"// 自定义一个Componoent,需要手动加载才会显示Component {// Component不能定义除id以外的其它属性id: buttonComponent// Component只能有一个顶层ItemRectangle {id: containerRectIdwidth: buttonTextId.implicitWidth + 60height: buttonTextId.implicitHeight + 20color: "#99CCFF"// 为内部的Text元素提供一个别名属性,方便在外部设置按钮的文本property alias buttonText: buttonTextId.textsignal buttonClicked()                                              // 自定义一个信号border {width: 1color: "#666666"}Text {id: buttonTextIdanchors.centerIn: parenttext: "按钮"font.pointSize: 16color: "#FF6666"}MouseArea {id: mouseAreaIdanchors.fill: parentonClicked: {containerRectId.buttonClicked()                                     // 触发信号}}}}
}

四、使用Loader动态加载组件

  Loader 用来动态加载 QML 组件。我们可以把 Loader 作为占位符使用,在需要显示某个元素时,才使用 Loader 把它加载进来。

  我们可以使用 Loader 的 source 属性 加载一个 QML 文档,也可以通过其 sourceComponent 属性 加载一个 Component 对象。当 Loader 的 source 或 sourceComponent 属性发生变化时,它之前加载的 Component 会自动销毁,新对象会被加载。将 source 设置为一个 空字符串 或将 sourceComponent 设置为 undefined,将会 销毁当前加载的对象,相关的资源也会被释放,而 Loader 对象则变成一个空对象。

  Loader 的 item 属性 指向它加载的组件的顶层 Item。对于 Loader 加载的 Item,它暴露出来的接口,如属性、信号等,都可以通过 Loader 的 item 属性来访问。

  虽然 Loader 本身是 Item 的派生类,但没有加载 Component 的 Loader 对象是不可见的,没什么实际的意义,只是个占位符号,而一旦你加载了一个 Component,Loader 的大小、位置等属性却可以影响它所加载的 Component。

  如果你没有显式指定 Loader 的大小,那么 Loader 会将自己的尺寸调整为与它加载的可见 Item 的尺寸一致。如果 Loader 的大小通过 width、height或锚布局显式设置了,那么它加载的可见 Item 的尺寸会被调整以便适应 Loader 的大小。不管是哪种情况,Loader 和它所加载的 Item 具有相同的尺寸,这确保你使用锚来布局 Loader 就等同于布局它加载的 Item。

  如果我们要加载的 Component 比较大,则可能比较卡顿。此时你可以设置 asynchronous 属性为 true 来 开启异步加载模式,当 status(枚举值)的值为 Loader.Ready 时表示 已经加载完毕。status 属性的取值如下:

Loader.Null
Loader.Ready 
Loader.Loading
Loader.Error

  如果 Loader 加载的 Item 想 处理按键事件,那么必须将 Loader 对象的 focus 属性设置为 true。又因为 Loader 本身也是一个焦点敏感的对象,所以如果它加载的 Item 处理了按键事件,则应当将事件的 accepted 属性设置为 true,以免已经被吃掉的事件再传递给 Loader。

  修改 template.qml 文件的内容。

import QtQuick.Window// Window控件表示一个顶级窗口
// 在QML中,元素是通过大括号{}内的属性来配置的。
Window {width: 800                                                                  // 窗口的宽度height: 600                                                                 // 窗口的高度visible: true                                                               // 显示窗口color: "lightgray"// 自定义一个Componoent,需要手动加载才会显示Component {// Component不能定义除id以外的其它属性id: buttonComponentId// Component只能有一个顶层ItemRectangle {id: containerRectIdwidth: buttonTextId.implicitWidth + 60height: buttonTextId.implicitHeight + 20color: "#99CCFF"// 为内部的Text元素提供一个别名属性,方便在外部设置按钮的文本property alias buttonText: buttonTextId.textsignal buttonClicked()                                              // 自定义一个信号border {width: 1color: "#666666"}Text {id: buttonTextIdanchors.centerIn: parenttext: "按钮"font.pointSize: 16color: "#FF6666"}MouseArea {id: mouseAreaIdanchors.fill: parentonClicked: {containerRectId.buttonClicked()                                     // 触发信号}}}}Text {id: textIdanchors.centerIn: parentfont.pointSize: 32color: "#FF6666"}Row {spacing: 20Loader {id: firstButtonIdsourceComponent: buttonComponentId                                  // 加载一个Component对象asynchronous: true                                                  // 异步加载// 加载完成后会触发loaded信号onLoaded: {var customButton = firstButtonId.item                           // 获取加载组件顶层的Item对象customButton.buttonText = "第一个按钮"customButton.buttonClicked.connect(function() {textId.text = "第一个按钮被点击了"})}}Loader {id: secondButtonIdsourceComponent: buttonComponentId                                  // 加载一个Component对象asynchronous: true                                                  // 异步加载// 加载完成后会触发loaded信号onLoaded: {var customButton = secondButtonId.item                          // 获取加载组件顶层的Item对象customButton.buttonText = "第二个按钮"customButton.buttonClicked.connect(function() {textId.text = "第二个按钮被点击了"})}}}
}

相关新闻

  • 详细介绍:Go 语言 + Word 文档模板:WordZero 引擎如何让企业文档处理效率提升 300%?
  • 2025 年储罐厂家推荐最新公司权威排行榜榜单发布,深度解析衬四氟储罐 / 硫酸储罐 / 盐酸储罐工厂选购指南
  • 实用指南:跳动的爱心

最新新闻

  • 2026全域外卖平台红黑榜真实横评,避坑攻略口碑实力双保障 - mypinpai
  • K2.5开源模型:面向生产级Agent系统的状态感知架构
  • 馨风尚包装源头工厂公司介绍与实力测评,零套路口碑之选 - myqiye
  • 交流电转直流电的电源电路
  • Python 开发者进阶 AI,除了语法还要补哪些课
  • 微前端赋能电力存量系统升级|Vue2渐进式迁移Vue3、双栈兼容架构、业务零停机方案、电网全场景落地实战、全套工程代码复现

日新闻

  • 5分钟掌握Python进化算法:Geatpy高性能优化工具完全指南
  • Microchip 24AA044 EEPROM选型与应用全指南:从参数解析到实战编程
  • 华为的鸿蒙到底有多牛?为什么称作遥遥领先?

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号