没有合适的资源?快使用搜索试试~ 我知道了~
首页Qt入门教程:十四步带你掌握GUI编程
Qt入门教程:十四步带你掌握GUI编程
需积分: 18 1 下载量 131 浏览量
更新于2024-07-21
收藏 494KB PDF 举报
本篇内容是针对初学者的Qt入门教程详解,适合那些已经具备C++基础的人士。教程分为两个阶段,首先推荐阅读Qt的官方白皮书,它提供了软件概述和一些示例代码片段,帮助理解Qt的基本概念。对于希望纯用C++编程,不依赖设计工具的开发者,教程1是一个基础课程,强调编码实践,逐步构建应用程序,从最初的HelloWorld程序扩展到更复杂的图形用户界面。 第二阶段,教程2深入介绍了实际应用,如菜单、工具栏、文件操作和对话框等组件的实现。对于希望利用设计工具设计界面的开发者,建议先阅读Qt设计器的手册,然后通过纯C++教程进一步提升技能。 在有一定项目经验后,建议读者深化理解Qt的核心概念,如对象模型和信号与槽机制,这有助于更好地管理和组织代码。浏览相关实例源代码和Qt源代码也是提升理解的好方法。通过运行Qt的demo程序,可以看到实际运行中的各种部件,直观感受Qt的强大功能。 整个教程共分为十四步,从简单的HelloWorld程序开始,逐步扩展至复杂的应用程序。即使是对Qt不太熟悉的读者,也可以从第一步开始,逐步跟随教程进入Qt的世界。文档中提供了详尽的API参考和导航选项,方便根据个人喜好和需求进行学习。 这篇教程不仅提供了实践指导,还强调了Qt编程的思维方式和关键特性的应用,旨在帮助读者掌握图形用户界面开发的基础技巧,为后续的项目开发打下坚实的基础。最后,作者祝愿读者在Qt的学习旅程中取得成功并享受编程的乐趣。
资源详情
资源推荐
![](https://csdnimg.cn/release/download_crawler_static/9273513/bgf.jpg)
{
public:
MyWidget( QWidget *parent=0, const char *name=0 );
};
MyWidget::MyWidget( QWidget *parent, const char *name )
: QVBox( parent, name )
{
QPushButton *quit = new QPushButton( "Quit", this, "quit" );
quit->setFont( QFont( "Times", 18, QFont::Bold ) );
connect( quit, SIGNAL(clicked()), qApp, SLOT(quit()) );
QGrid *grid = new QGrid( 4, this );
for( int r = 0 ; r < 4 ; r++ )
for( int c = 0 ; c < 4 ; c++ )
(void)new LCDRange( grid );
}
int main( int argc, char **argv )
{
QApplication a( argc, argv );
MyWidget w;
a.setMainWidget( &w );
w.show();
return a.exec();
}
一行一行地解说
class LCDRange : public QVBox
{
public:
LCDRange( QWidget *parent=0, const char *name=0 );
};
LCDRange 窗口部件是一个没有任何 API 的窗口部件。它只有一个构造函数。这
种窗口部件不是很有用,所以我们一会儿会加入一些 API。
LCDRange::LCDRange( QWidget *parent, const char *name )
: QVBox( parent, name )
{
QLCDNumber *lcd = new QLCDNumber( 2, this, "lcd" );
![](https://csdnimg.cn/release/download_crawler_static/9273513/bg10.jpg)
QSlider * slider = new QSlider( Horizontal, this, "slider" );
slider->setRange( 0, 99 );
slider->setValue( 0 );
connect( slider, SIGNAL(valueChanged(int)), lcd, SLOT(display(int)) );
}
这里直接利用了第五章里面的 MyWidget 的构造函数。唯一的不同是按钮被省略
了并且这个类被重新命名了。
class MyWidget : public QVBox
{
public:
MyWidget( QWidget *parent=0, const char *name=0 );
};
MyWidget 也是除了一个构造函数之外没有包含任何 API。
MyWidget::MyWidget( QWidget *parent, const char *name )
: QVBox( parent, name )
{
QPushButton *quit = new QPushButton( "Quit", this, "quit" );
quit->setFont( QFont( "Times", 18, QFont::Bold ) );
connect( quit, SIGNAL(clicked()), qApp, SLOT(quit()) );
这个按钮被放在 LCDRange 中,这样我们就有了一个“Quit”按钮和许多
LCDRange 对象。
QGrid *grid = new QGrid( 4, this );
我们创建了一个四列的 QGrid 对象。这个 QGrid 窗口部件可以自动地把自己地
子窗口部件排列到行列中,你可以指定行和列的数量,并且 QGrid 可以发现它的
新子窗口部件并且把它们安放到网格中。
for( int r = 0 ; r < 4 ; r++ )
for( int c = 0 ; c < 4 ; c++ )
(void)new LCDRange( grid );
四行,四列。
我们创建了一个 4*4 个 LCDRanges,所有这些都是这个 grid 对象的子窗口部件。
这个 QGrid 窗口部件会安排它们。
}
这就是全部了。
行为
这个程序显示了在同一时间使用许多窗口部件是多么的容易。其中的滑块和
LCD 数字的行为在前一章已经提到过了。还有就是,就是实现的不同。
(请看编译来学习如何创建一个 makefile 和连编应用程序。)
练习
![](https://csdnimg.cn/release/download_crawler_static/9273513/bg11.jpg)
在开始的时候使用不同的或者随机的值初始化每个滑块。
源代码中的“4”出现了 3 次。如果你改变 QGrid 构造函数中调用的那个,会发
生什么?改变另外两个又会发生什么呢?为什么呢?
现在你可以进行第七章了。
Qt 教程一 —— 第七章:一个事物领导
另一个
这个例子显示了如何使用信号和槽来创建自定义窗口部件,和如何使用更加复杂
的方式把它们连接起来。首先,源文件被我们分成几部分并放在放在 t7 目录下。
• t7/lcdrange.h 包含 LCDRange 类定义。
• t7/lcdrange.cpp 包含 LCDRange 类实现。
• t7/main.cpp 包含 MyWidget 和 main。
一行一行地解说
t7/lcdrange.h
这个文件主要利用了第六章的 main.cpp,在这里只是说明一下改变了哪些。
#ifndef LCDRANGE_H
#define LCDRANGE_H
这里是一个经典的 C 语句,为了避免出现一个头文件被包含不止一次的情况。
如果你没有使用过它,这是开发中的一个很好的习惯。#ifndef 需要把这个头文
件的
全部
都包含进去。
#include <qvbox.h>
qvbox.h 被包含了。LCDRange 继承了 QVBox,所以父类的头文件必须被包含。
我们在前几章里面偷了一点懒,我们通过包含其它一些头文件,比如
qpushbutton.h,这样就可以间接地包含 qwidget.h。
class QSlider;
![](https://csdnimg.cn/release/download_crawler_static/9273513/bg12.jpg)
这里是另外一个小伎俩,但是没有前一个用的多。因为我们在类的
界面
中不需要
QSlider,仅仅是在实现中,我们在头文件中使用一个前置的类声明,并且在.cpp
文件中包含一个 QSlider 的头文件。
这会使编译一个大的项目变得更快,因为当一个头文件改变的时候,很少的文件
需要重新编译。它通常可以给大型编译加速两倍或两倍以上。
class LCDRange : public QVBox
{
Q_OBJECT
public:
LCDRange( QWidget *parent=0, const char *name=0 );
meta object file. 注意 Q_OBJECT。这个宏必须被包含到
所有
使用信号和/或槽的
类。如果你很好奇,它定义了在元对象文件中实现的一些函数。
int value() const;
public slots:
void setValue( int );
signals:
void valueChanged( int );
这三个成员函数构成了这个窗口部件和程序中其它组件的接口。直到现在,
LCDRange 根本没有一个真正的接口。
value()是一个可以访问 LCDRange 的值的公共函数。setValue()是我们第一个自定
义槽,并且 valueChanged()是我们第一个自定义信号。
槽必须按通常的方式实现(记住槽也是一个 C++成员函数)。信号可以在元对象
文件中自动实现。信号也遵守 C++函数的保护法则(比如,一个类只能发射它自
己定义的或者继承来的信号)。
当 LCDRange 的值发生变化时,valueChanged()信号就会被使用——你从这个名
字中就可以猜到。这将不会是你将会看到的命名为 somethingChanged()的最后一
个信号。
t7/lcdrange.cpp
这个文件主要利用了 t6/main.cpp,在这里只是说明一下改变了哪些。
connect( slider, SIGNAL(valueChanged(int)),
lcd, SLOT(display(int)) );
connect( slider, SIGNAL(valueChanged(int)),
SIGNAL(valueChanged(int)) );
这个代码来自 LCDRange 的构造函数。
第一个 connect 和你在上一章中看到的一样。第二个是新的,它把滑块的
valueChanged()信号和这个对象的 valueChanged
信号
连接起来了。带有三个参数
的 connect()函数连接到 this 对象的信号或槽。
是的,这是正确的。信号可以被连接到其它的信号。当第一个信号被发射时,第
二个信号也被发射。
![](https://csdnimg.cn/release/download_crawler_static/9273513/bg13.jpg)
让我们来看看当用户操作这个滑块的时候都发生了些什么。滑块看到自己的值发
生了改变,并发射了 valueChanged()信号。这个信号被连接到 QLCDNumber 的
display()槽和 LCDRange 的 valueChanged()信号。
所以,当这个信号被发射的时候,LCDRange 发射它自己的 valueChanged()信号。
另外,QLCDNumber::display()被调用并显示新的数字。
注意你并没有保证执行的任何顺序——LCDRange::valueChanged()也许在
QLCDNumber::display()之前或者之后发射,这是完全任意的。
int LCDRange::value() const
{
return slider->value();
}
value()的实现是直接了当的,它简单地返回滑块的值。
void LCDRange::setValue( int value )
{
slider->setValue( value );
}
setValue()的实现是相当直接了当的。注意因为滑块和 LCD 数字是连接的,设置
滑块的值就会自动的改变 LCD 数字的值。另外,如果滑块的值超过了合法范围,
它会自动调节。
t7/main.cpp
LCDRange *previous = 0;
for( int r = 0 ; r < 4 ; r++ ) {
for( int c = 0 ; c < 4 ; c++ ) {
LCDRange* lr = new LCDRange( grid );
if ( previous )
connect( lr, SIGNAL(valueChanged(int)),
previous, SLOT(setValue(int)) );
previous = lr;
}
}
main.cpp 中所有的部分都是上一章复制的,除了 MyWidget 的构造函数。当我们
创建 16 个 RCDRange 对象时,我们现在使用信号/槽机制连接它们。每一个的
valueChanged()信号都和前一个的 setValue()槽连接起来了。因为当 LCDRange 的
值发生改变的时候,发射一个 valueChanged()信号(惊奇!),我们在这里创建
了一个信号和槽的“链”。
编译
为一个多文件的应用程序创建一个 makefile 和为一个单文件的应用程序创建一
个 makefile 是没有什么不同的。如果你已经把这个例子中的所有文件都保存到它
们自己的目录中,你所要做的就是这些:
qmake -project
剩余90页未读,继续阅读
![application/msword](https://img-home.csdnimg.cn/images/20210720083327.png)
![pdf](https://img-home.csdnimg.cn/images/20210720083512.png)
![-](https://img-home.csdnimg.cn/images/20210720083327.png)
![-](https://img-home.csdnimg.cn/images/20210720083327.png)
![-](https://csdnimg.cn/download_wenku/file_type_column_c1.png)
![-](https://csdnimg.cn/download_wenku/file_type_column_c1.png)
![-](https://csdnimg.cn/download_wenku/file_type_column_c1.png)
![-](https://csdnimg.cn/download_wenku/file_type_column_c1.png)
![-](https://csdnimg.cn/download_wenku/file_type_column_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://profile-avatar.csdnimg.cn/default.jpg!1)
天阔victor
- 粉丝: 0
- 资源: 2
上传资源 快速赚钱
我的内容管理 展开
我的资源 快来上传第一个资源
我的收益
登录查看自己的收益我的积分 登录查看自己的积分
我的C币 登录后查看C币余额
我的收藏
我的下载
下载帮助
![](https://csdnimg.cn/release/wenkucmsfe/public/img/voice.245cc511.png)
最新资源
- 多模态联合稀疏表示在视频目标跟踪中的应用
- Kubernetes资源管控与Gardener开源软件实践解析
- MPI集群监控与负载平衡策略
- 自动化PHP安全漏洞检测:静态代码分析与数据流方法
- 青苔数据CEO程永:技术生态与阿里云开放创新
- 制造业转型: HyperX引领企业上云策略
- 赵维五分享:航空工业电子采购上云实战与运维策略
- 单片机控制的LED点阵显示屏设计及其实现
- 驻云科技李俊涛:AI驱动的云上服务新趋势与挑战
- 6LoWPAN物联网边界路由器:设计与实现
- 猩便利工程师仲小玉:Terraform云资源管理最佳实践与团队协作
- 类差分度改进的互信息特征选择提升文本分类性能
- VERITAS与阿里云合作的混合云转型与数据保护方案
- 云制造中的生产线仿真模型设计与虚拟化研究
- 汪洋在PostgresChina2018分享:高可用 PostgreSQL 工具与架构设计
- 2018 PostgresChina大会:阿里云时空引擎Ganos在PostgreSQL中的创新应用与多模型存储
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
![](https://img-home.csdnimg.cn/images/20220527035711.png)
![](https://img-home.csdnimg.cn/images/20220527035711.png)
![](https://img-home.csdnimg.cn/images/20220527035111.png)
安全验证
文档复制为VIP权益,开通VIP直接复制
![](https://csdnimg.cn/release/wenkucmsfe/public/img/green-success.6a4acb44.png)