适合人群: 已安装 Qt,想动手跑出第一个真实程序的新手
前言
前几篇我们了解了 Qt 的产品体系和构建工具,现在终于到了动手的时刻。
本文目标只有一个:在 Qt Creator 里创建一个 Qt Quick 项目,添加几个 QML 组件,让它成功运行起来。不追求完美,只追求跑通------跑通之后,一切都会变得具体。
一、Qt Quick 是什么?
在动手之前,先用一句话区分两个容易混淆的概念:
- QML:一种声明式编程语言,描述"界面长什么样、怎么交互"
- Qt Quick:基于 QML 的 UI 框架,提供了矩形、图片、文本、动画等一系列可直接使用的视觉元素
可以把 QML 理解为语言,Qt Quick 理解为用这门语言写成的标准组件库。写 Qt Quick 应用,本质上就是在写 QML 代码。
二、在 Qt Creator 中新建项目
第一步:打开新建项目向导
启动 Qt Creator,点击欢迎界面的 "Create Project" ,或菜单 File → New Project。
第二步:选择项目模板
在模板列表中选择:
scss
Application (Qt)
└── Qt Quick Application
点击 Choose...
第三步:填写项目信息
| 字段 | 填写内容 |
|---|---|
| Name | MyFirstApp(不要有空格和中文) |
| Location | 选择一个路径(避免中文路径) |
点击 Next。
第四步:选择构建系统
选择 CMake (Qt 6 推荐,与上一篇一致),点击 Next。
第五步:选择 Qt 版本
选择你安装的 Qt 版本(如 Qt 6.7.0),点击 Next ,再点击 Finish。
项目创建完成,Qt Creator 会自动打开生成的文件。
三、认识自动生成的项目结构
创建完成后,左侧项目面板显示:
css
MyFirstApp
├── CMakeLists.txt ← 构建配置文件
└── Main.qml ← 主界面文件
main.cpp ← C++ 入口文件
main.cpp --- 程序入口
arduino
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
const QUrl url(u"qrc:/MyFirstApp/Main.qml"_s);
QObject::connect(
&engine,
&QQmlApplicationEngine::objectCreationFailed,
&app,
[](const QUrl &url) {
qWarning() << "Failed to load:" << url;
QCoreApplication::exit(-1);
},
Qt::QueuedConnection);
engine.load(url);
return app.exec();
}
这个文件基本不需要修改。它做了三件事:
- 创建
QGuiApplication应用实例(管理整个程序的生命周期) - 创建
QQmlApplicationEngine引擎(负责加载和运行 QML) - 加载
Main.qml作为根界面,启动事件循环
Main.qml --- 主界面
arduino
import QtQuick
import QtQuick.Controls
ApplicationWindow {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
}
这就是你的第一个窗口。现在它是空的,接下来我们往里面加内容。
四、第一次运行
点击左下角绿色三角形 Run (或按 Ctrl+R)。
等待片刻,一个 640×480 的空白窗口应该出现在屏幕上------标题栏显示"Hello World"。
恭喜,Qt Quick 应用跑起来了。
如果没有弹出窗口,检查底部 "Compile Output" 面板,查看报错信息。最常见的问题是 Kit 未正确配置,回到 Preferences → Kits 检查编译器是否有绿色对勾。
五、添加第一个 QML 组件:文本
打开 Main.qml,在 ApplicationWindow 内部添加一个 Text 组件:
less
import QtQuick
import QtQuick.Controls
ApplicationWindow {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Text {
anchors.centerIn: parent
text: "你好,Qt Quick!"
font.pixelSize: 28
color: "#333333"
}
}
按 Ctrl+R 重新运行,窗口中央会出现文字"你好,Qt Quick!"。
解析这段代码
anchors.centerIn: parent:将这个元素居中于父元素(即窗口)font.pixelSize: 28:字体大小 28 像素color: "#333333":深灰色,支持十六进制颜色值
六、添加按钮和交互
光显示文字还不够,加一个按钮,点击时改变文字内容:
less
import QtQuick
import QtQuick.Controls
ApplicationWindow {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Column {
anchors.centerIn: parent
spacing: 20
Text {
id: myText
anchors.horizontalCenter: parent.horizontalCenter
text: "你好,Qt Quick!"
font.pixelSize: 28
color: "#333333"
}
Button {
anchors.horizontalCenter: parent.horizontalCenter
text: "点我"
onClicked: {
myText.text = "按钮被点击了!"
myText.color = "#1D9E75"
}
}
}
}
运行后点击按钮,文字会变成绿色的"按钮被点击了!"。
新增知识点
Column :垂直排列子元素的布局容器,spacing: 20 设置子元素间距为 20 像素。
id: myText:给元素取一个唯一标识符,方便其他地方引用它。
onClicked :按钮的点击信号处理器。Qt Quick 中所有交互都通过信号和处理器实现------信号名前加 on 就是对应的处理器名称。
七、添加输入框:实现实时文字同步
再进一步,用 TextField 实现输入框内容与文本的实时同步:
less
import QtQuick
import QtQuick.Controls
ApplicationWindow {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Column {
anchors.centerIn: parent
spacing: 20
width: 300
TextField {
id: inputField
width: parent.width
placeholderText: "在这里输入内容..."
font.pixelSize: 16
}
Text {
width: parent.width
text: inputField.text !== "" ? inputField.text : "等待输入..."
font.pixelSize: 24
color: "#333333"
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.Wrap
}
}
}
运行后在输入框里打字,下方文字会实时跟随变化。
核心概念:属性绑定
arduino
text: inputField.text !== "" ? inputField.text : "等待输入..."
这行代码展示了 QML 最重要的特性之一------属性绑定 。text 的值不是一次性赋值,而是始终保持与 inputField.text 的动态关联。只要输入框内容变化,这里的文字自动更新,无需手动监听事件。
这是 QML 与传统命令式 UI 编程最大的区别,也是 QML 代码简洁的根本原因。
八、添加图片资源
在项目中显示一张图片需要两步:把图片加入项目,然后在 QML 中引用。
第一步:添加图片文件
将图片文件(如 logo.png)复制到项目目录下,例如放在 images/ 子目录中。
第二步:在 CMakeLists.txt 中注册
打开 CMakeLists.txt,在 qt_add_qml_module 中添加:
scss
qt_add_qml_module(MyFirstApp
URI MyFirstApp
VERSION 1.0
QML_FILES
Main.qml
RESOURCES
images/logo.png
)
第三步:在 QML 中使用
yaml
Image {
anchors.horizontalCenter: parent.horizontalCenter
source: "images/logo.png"
width: 120
height: 120
fillMode: Image.PreserveAspectFit
}
fillMode: Image.PreserveAspectFit 表示保持图片原始宽高比进行缩放,不会拉伸变形。
九、弹出对话框
Qt Quick Controls 提供了现成的弹窗组件:
yaml
import QtQuick
import QtQuick.Controls
ApplicationWindow {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Button {
anchors.centerIn: parent
text: "显示弹窗"
onClicked: dialog.open()
}
Dialog {
id: dialog
anchors.centerIn: parent
title: "提示"
modal: true
Label {
text: "这是一个弹出对话框!"
}
standardButtons: Dialog.Ok
}
}
modal: true 表示弹窗为模态------弹出时用户必须先关闭它才能操作其他界面元素。
十、完整示例:把以上内容整合
yaml
import QtQuick
import QtQuick.Controls
ApplicationWindow {
width: 640
height: 480
visible: true
title: qsTr("我的第一个 Qt Quick 应用")
Column {
anchors.centerIn: parent
spacing: 16
width: 320
Text {
anchors.horizontalCenter: parent.horizontalCenter
text: "Qt Quick 入门示例"
font.pixelSize: 22
font.bold: true
color: "#222222"
}
TextField {
id: nameInput
width: parent.width
placeholderText: "输入你的名字"
font.pixelSize: 15
}
Button {
width: parent.width
text: "打招呼"
onClicked: {
if (nameInput.text !== "") {
greetDialog.open()
}
}
}
}
Dialog {
id: greetDialog
anchors.centerIn: parent
title: "你好!"
modal: true
Label {
text: "欢迎来到 Qt Quick," + nameInput.text + "!"
font.pixelSize: 16
}
standardButtons: Dialog.Ok
}
}
运行后,在输入框填写名字,点击"打招呼",弹出包含姓名的问候对话框。
十一、常见问题
Q:修改 QML 后不需要重新编译吗?
QML 文件的修改通常不需要完整重新编译,Qt Creator 的 QML 热重载功能可以在不重启应用的情况下刷新界面。点击运行时工具栏的"重新加载 QML"按钮即可。
但修改 CMakeLists.txt 或 C++ 文件后,必须重新编译。
Q:anchors.centerIn: parent 和 anchors.horizontalCenter: parent.horizontalCenter 有什么区别?
anchors.centerIn: parent:水平 + 垂直都居中anchors.horizontalCenter: parent.horizontalCenter:只水平居中,垂直位置不受影响
Q:qsTr() 是什么?
qsTr() 是 Qt 的国际化函数,标记这段文字需要翻译。即使现在不做多语言支持,养成用 qsTr() 包裹用户可见字符串的习惯,以后国际化会容易很多。
十二、下一步
现在你已经能创建窗口、添加文本、处理点击事件、使用输入框和弹窗了。接下来建议:
- Introduction to QML --- 系统学习 QML 语法,理解属性绑定、信号、组件的完整概念
- Qt Quick vs. Widgets --- 了解什么场景用 Qt Quick,什么场景用 Qt Widgets
- Positioners and Layouts --- 学习更强大的布局方式,让 UI 适配不同屏幕尺寸
总结
| 组件 | 用途 |
|---|---|
ApplicationWindow |
应用主窗口容器 |
Text |
显示文字 |
Button |
可点击按钮,onClicked 处理点击 |
TextField |
单行文本输入框 |
Column |
垂直排列子元素 |
Image |
显示图片 |
Dialog |
弹出对话框 |
anchors |
定位系统,控制元素位置 |
| 属性绑定 | a: b.value 让属性自动跟随另一个属性变化 |