Qt Quick 常用控件入门:Window、Control、Button、CheckBox 与 RadioButton
2. 本节学习目标
本节主要学习以下内容:
Window和ApplicationWindow的作用区别- Qt Quick 控件的基本继承关系
Control在控件体系中的作用Button的常用属性、信号和自定义样式CheckBox的状态处理和样式自定义RadioButton的使用场景和样式自定义- Qt Quick 默认控件为什么在真实项目中经常需要重写样式
3. Qt Quick 控件的整体关系
在 Qt Quick 中,很多常用控件都来自 QtQuick.Controls 模块。
从继承关系上可以简单理解为:
text
QObject
-> Item
-> Control
-> AbstractButton
-> Button
-> CheckBox
-> RadioButton
这里有几个关键点:
QObject是 Qt 对象体系的基础。Item是 QML 可视化对象的基础类型。Control是 Qt Quick Controls 中多数控件的基类。AbstractButton是按钮类控件的抽象基类。Button、CheckBox、RadioButton都属于按钮体系。
补充理解:
QML 和 QWidget 都属于 Qt 技术体系,但它们是两套不同的 UI 开发方式。QWidget 更偏传统桌面软件开发,而 QML 更偏声明式界面开发,常用于移动端、嵌入式、车载 HMI 和动态 UI 场景。
4. Window:Qt Quick 的顶级窗口
4.1 Window 是什么
Window 是 Qt Quick 中用于创建顶级窗口的类型。一个 QML 程序想要显示出来,通常需要一个窗口作为最外层承载对象。
可以把 Window 理解成整个 QML 界面的外壳。
示例代码:
qml
import QtQuick
Window {
width: 1024
height: 600
visible: true
title: "Qt Quick Demo"
}
常用属性:
width:窗口宽度height:窗口高度visible:是否显示窗口title:窗口标题flags:窗口标志位,比如是否显示标题栏
初学者最容易忘的是:
qml
visible: true
如果没有设置 visible: true,程序可能已经运行了,但是窗口不会显示出来。
4.2 无标题栏窗口
在桌面应用中,窗口默认会有标题栏。但在嵌入式、车载 HMI、触摸屏项目中,界面通常是全屏或无边框的。
常见写法:
qml
import QtQuick
Window {
width: 1024
height: 600
visible: true
flags: Qt.FramelessWindowHint
}
Qt.FramelessWindowHint 表示创建无边框窗口。
在车载 HMI 项目中,如果整个屏幕都由 QML 界面接管,就经常会使用无标题栏窗口。
4.3 closing 信号
当窗口关闭时,会触发 closing 信号。可以在这个信号中做退出前处理,比如保存数据、记录日志、释放资源等。
示例:
qml
import QtQuick
Window {
width: 1024
height: 600
visible: true
onClosing: function(close) {
console.log("window is closing")
}
}
在普通桌面程序里,onClosing 比较常见;在车载 HMI 中,窗口本身通常不会频繁关闭,更多是页面切换和状态切换。
5. ApplicationWindow:更完整的应用窗口
ApplicationWindow 是 Window 的子类,它在 Window 的基础上增加了更完整的应用窗口结构。
它常见的能力包括:
menuBarheaderfooter
使用 ApplicationWindow 时需要导入:
qml
import QtQuick.Controls
示例代码:
qml
import QtQuick
import QtQuick.Controls
ApplicationWindow {
width: 1024
height: 600
visible: true
title: "Application Window Demo"
header: ToolBar {
Label {
text: "Header"
anchors.centerIn: parent
}
}
footer: ToolBar {
Label {
text: "Footer"
anchors.centerIn: parent
}
}
}
ApplicationWindow 更适合带菜单栏、工具栏、状态栏的桌面应用结构。
不过在移动端、嵌入式、车载 HMI 项目中,很多时候不会直接使用传统桌面式结构,而是自己用 Window + Item + Loader + 自定义组件 搭建页面系统。
6. Control:Qt Quick 控件的基类型
6.1 Control 的作用
Control 是 Qt Quick Controls 中很多控件的基类。
一般情况下,我们不会直接这样写:
qml
Control {
}
因为 Control 本身更像一个控件基础框架。它提供了一些通用能力,比如内容区域、背景、内边距等,但具体可见效果通常由子类控件实现。
实际开发中更常用的是:
qml
Button {}
CheckBox {}
RadioButton {}
Label {}
TextField {}
6.2 contentItem、background、padding、inset
理解 Control,重点要理解几个概念。
contentItem 表示控件内容区域。比如按钮中的文字、复选框旁边的文本,都可以通过 contentItem 自定义。
background 表示控件背景。比如按钮的矩形底色、圆角、图片背景等。
padding 表示内容区域和控件边界之间的内边距,常见属性包括:
topPaddingbottomPaddingleftPaddingrightPadding
inset 表示背景和控件边界之间的偏移,常见属性包括:
topInsetbottomInsetleftInsetrightInset
这部分对自定义样式非常重要。
很多时候控件看起来"不居中""文字贴边""图标和文字间距不对",本质上都是 contentItem、background、padding 没处理好。
7. Button:最常用的按钮控件
7.1 Button 是什么
Button 是 UI 开发中最常用的控件之一,用于响应点击、按下、释放、长按等操作。
简单示例:
qml
import QtQuick
import QtQuick.Controls
Button {
text: "确定"
onClicked: {
console.log("button clicked")
}
}
Button 继承自 AbstractButton,所以很多按钮相关属性和信号其实来自 AbstractButton。
7.2 Button 常用属性
常用属性包括:
width:按钮宽度height:按钮高度enabled:是否可用text:按钮显示文本down:按钮是否处于按下状态autoRepeat:是否开启长按重复触发autoRepeatInterval:长按重复触发间隔
示例:
qml
Button {
width: 160
height: 48
text: "长按测试"
autoRepeat: true
autoRepeatInterval: 200
onClicked: {
console.log("clicked")
}
}
enabled 很常用。当设置为 false 时,按钮不可点击,也不会响应点击事件。
qml
Button {
text: "不可点击"
enabled: false
}
7.3 Button 常用信号
按钮常见信号包括:
pressedreleasedclickeddoubleClickedpressAndHoldtoggled
示例:
qml
Button {
text: "按钮"
onPressed: {
console.log("pressed")
}
onReleased: {
console.log("released")
}
onClicked: {
console.log("clicked")
}
onPressAndHold: {
console.log("press and hold")
}
}
一般情况下,信号触发顺序可以理解为:
text
pressed -> released -> clicked
如果是长按,则中间可能触发:
text
pressed -> pressAndHold -> released -> clicked
在桌面平台中,双击比较常见,比如双击打开应用;但在嵌入式触摸屏、车载 HMI 中,通常不建议依赖双击,因为触摸屏上的双击体验不稳定,也不利于安全交互。
7.4 自定义 Button 样式
真实项目中,很少直接使用默认按钮样式。尤其是车载 HMI,按钮通常来自 UI 设计稿,需要自己定义背景、圆角、图片、文字样式和状态变化。
一个简单的圆角按钮示例:
qml
Button {
id: root
width: 180
height: 56
text: "播放"
background: Rectangle {
radius: 8
color: root.down ? "#2E7D32" : "#43A047"
}
contentItem: Text {
text: root.text
color: "white"
font.pixelSize: 20
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
这个例子中:
background控制按钮背景。contentItem控制按钮文字。root.down判断按钮是否处于按下状态。
7.5 播放/暂停按钮状态切换
课程中提到了一个播放器按钮示例:点击按钮后,在播放和暂停之间切换,并显示不同图片。
可以用一个布尔属性保存状态:
qml
Button {
id: playButton
width: 80
height: 80
property bool playing: false
background: Image {
anchors.fill: parent
source: playButton.playing ? "pause.png" : "play.png"
fillMode: Image.PreserveAspectFit
}
contentItem: Item {}
onClicked: {
playing = !playing
}
}
这个例子的核心思想是:
text
状态变化 -> 属性变化 -> 图片变化 -> UI 自动刷新
这也是 QML 很重要的写法。不要总想着手动刷新界面,而是让界面绑定到状态。
8. CheckBox:复选框控件
8.1 CheckBox 是什么
CheckBox 是复选框,用于表示选中或未选中。
常见场景:
- 设置页中开启或关闭某个功能
- 多选配置项
- 协议勾选
- 车辆功能开关
简单示例:
qml
import QtQuick
import QtQuick.Controls
CheckBox {
text: "开启自动大灯"
onCheckedChanged: {
console.log("checked:", checked)
}
}
8.2 checked 与 checkState
CheckBox 常用两个状态相关属性:
checked:是否选中,布尔值checkState:更完整的枚举状态
checkState 通常有三种状态:
Qt.UncheckedQt.PartiallyCheckedQt.Checked
普通项目里最常用的是选中和未选中,也就是二态复选框。
示例:
qml
CheckBox {
text: "自动连接"
checked: true
onCheckedChanged: {
console.log("auto connect:", checked)
}
}
如果只是关心选中状态变化,优先使用:
qml
onCheckedChanged
8.3 自定义 CheckBox 样式
课程重点强调了 CheckBox 自定义样式的必要性。
Qt Quick 自带的 CheckBox 样式依赖平台,视觉效果比较基础。真实产品中,UI 设计师通常会给出明确的选中图标、未选中图标、禁用状态和文字颜色要求。
在 QML 中,常用 indicator 自定义复选框前面的勾选区域。
示例:
qml
CheckBox {
id: checkBox
text: "记住选择"
indicator: Rectangle {
width: 24
height: 24
radius: 4
border.width: 2
border.color: checkBox.checked ? "#1E88E5" : "#999999"
color: checkBox.checked ? "#1E88E5" : "transparent"
Text {
anchors.centerIn: parent
text: checkBox.checked ? "✓" : ""
color: "white"
font.pixelSize: 18
}
}
contentItem: Text {
text: checkBox.text
color: checkBox.enabled ? "white" : "#777777"
font.pixelSize: 20
leftPadding: checkBox.indicator.width + 12
verticalAlignment: Text.AlignVCenter
}
}
这个例子中:
indicator控制左侧复选框图标。contentItem控制右侧文字。checked决定选中样式。enabled决定禁用样式。
如果项目里有图片资源,也可以用 Image 替代 Rectangle。
9. RadioButton:单选框控件
9.1 RadioButton 是什么
RadioButton 是单选按钮。它和 CheckBox 很像,但使用场景不同。
CheckBox 适合多选:
text
可同时选择 A、B、C
RadioButton 适合单选:
text
只能在 A、B、C 中选一个
常见场景:
- 语言选择
- 主题选择
- 驾驶模式选择
- 单位选择,比如 km/h 或 mph
示例:
qml
Column {
RadioButton {
text: "中文"
checked: true
}
RadioButton {
text: "English"
}
RadioButton {
text: "Deutsch"
}
}
同一个父级下的多个 RadioButton 通常会表现出互斥选择效果。如果项目结构复杂,也可以配合 ButtonGroup 明确管理一组单选按钮。
9.2 RadioButton 常用属性与信号
RadioButton 也继承自 AbstractButton,所以常用属性和 CheckBox 类似:
widthheightenabledtextcheckedcheckState
状态变化时可以这样处理:
qml
RadioButton {
text: "中文"
onCheckedChanged: {
if (checked) {
console.log("language: zh_CN")
}
}
}
注意:
单选按钮一般只关心"被选中"的时刻,所以常见写法是:
qml
if (checked) {
// 执行选中后的逻辑
}
否则取消选中时也会触发一次状态变化,容易误处理。
9.3 自定义 RadioButton 样式
RadioButton 的自定义思路和 CheckBox 类似,也是重点改 indicator 和 contentItem。
示例:
qml
RadioButton {
id: radio
text: "舒适模式"
indicator: Rectangle {
width: 24
height: 24
radius: 12
border.width: 2
border.color: radio.checked ? "#00C853" : "#999999"
color: "transparent"
Rectangle {
width: 12
height: 12
radius: 6
anchors.centerIn: parent
visible: radio.checked
color: "#00C853"
}
}
contentItem: Text {
text: radio.text
color: radio.enabled ? "white" : "#777777"
font.pixelSize: 20
leftPadding: radio.indicator.width + 12
verticalAlignment: Text.AlignVCenter
}
}
这里用两个圆形 Rectangle 组成单选框:
- 外层圆表示按钮边框。
- 内层圆表示选中状态。
visible: radio.checked控制内层圆是否显示。
10. 常见问题与踩坑
问题 1:Window 写了但窗口不显示
现象:
程序运行了,但是看不到窗口。
原因:
可能忘记写:
qml
visible: true
解决:
qml
Window {
width: 1024
height: 600
visible: true
}
复习时记住:
Window 是顶级窗口,但默认不一定显示,初学时先检查 visible。
问题 2:默认控件样式不好看
现象:
Button、CheckBox、RadioButton 默认样式和设计稿差距很大。
原因:
Qt Quick Controls 的默认样式偏通用,不一定适合车载 HMI 或产品级界面。
解决:
根据控件类型自定义:
Button:重点改background和contentItemCheckBox:重点改indicator和contentItemRadioButton:重点改indicator和contentItem
复习时记住:
真实项目里,控件默认样式通常只是功能验证用,最终大多要按 UI 设计稿重写。
问题 3:Button 的 clicked、pressed、released 分不清
现象:
不知道应该把逻辑写在 onClicked、onPressed 还是 onReleased。
原因:
这些信号关注的时机不同。
解决:
- 点击完成后执行逻辑:用
onClicked - 按下瞬间改变视觉状态:用
onPressed或绑定down - 松手时处理:用
onReleased - 长按逻辑:用
onPressAndHold或autoRepeat
复习时记住:
大多数普通按钮业务逻辑写在 onClicked 就够了。
问题 4:CheckBox 和 RadioButton 不知道怎么选
现象:
设置页里不知道该用复选框还是单选框。
原因:
两者都是按钮体系控件,但选择语义不同。
解决:
- 可以同时选择多个:用
CheckBox - 一组选项只能选一个:用
RadioButton
示例:
text
是否开启自动大灯:CheckBox
语言选择:RadioButton
11. 小结
这节课的主线很清楚:
先从顶层窗口 Window 讲起,再介绍更完整的 ApplicationWindow,然后进入 Qt Quick Controls 的基础类型 Control,最后讲三个最常用的按钮体系控件:Button、CheckBox、RadioButton。
需要重点掌握的是:
Window是顶级窗口,初学时记得设置visible: true。ApplicationWindow更偏桌面应用窗口结构。Control是很多控件的基类,理解它有助于理解自定义样式。Button是最常用控件,重点掌握属性、信号和样式重写。CheckBox用于多选或开关类选项。RadioButton用于一组选项中的单选。- 真实产品开发中,默认控件样式通常无法满足需求,自定义样式是重点。
对车载 HMI 或嵌入式界面开发来说,最重要的不是"会拖一个按钮出来",而是能把按钮、状态、图片、文字、禁用态、选中态、按下态都封装成稳定可复用的组件。
12. 复习清单
Window的作用是什么?- 为什么
Window经常要写visible: true? ApplicationWindow比Window多了哪些结构?- 为什么 Qt Quick 更偏移动端、嵌入式和 HMI?
Control、Item、QObject之间大概是什么继承关系?contentItem和background分别负责什么?padding和inset有什么区别?Button常用属性有哪些?pressed、released、clicked的触发关系是什么?autoRepeat适合什么场景?- 如何自定义一个 Button 的背景和文字?
CheckBox的checked和checkState有什么区别?CheckBox的indicator通常用来改什么?RadioButton和CheckBox的使用场景区别是什么?- 为什么真实项目里经常不用默认控件样式?
- 如果要做车载 HMI 设置页,哪些控件适合封装成自定义组件?