QT开发(简洁版)

0. QT背景介绍

0.1 什么是QT

Qt 是⼀个 跨平台的 C++ 图形⽤⼾界⾯应⽤程序框架
开发者可以通过简单的 拖拽 组合 来实现复杂的应⽤程序,

0.2 Qt 的发展史 && 支持平台

  • 1991 年 Qt 最早由奇趣科技开发
  • 1996 年 进⼊商业领域,它也是⽬前流⾏的 Linux 桌⾯环境 KDE 的基础;
  • 2008 年 奇趣科技被诺基亚公司收购,Qt 成为诺基亚旗下的编程⼯具;
  • 2012 年 Qt ⼜被 Digia 公司收购;
  • 2014 年 4 ⽉ 跨平台的集成开发环境 Qt Creator3.1.0 发布,同年 5 ⽉ 20 ⽇发布了 Qt 5.3 正式版,⾄此 Qt 实现了对 IOS、Android、Embedded 等各平台的全⾯⽀持。

  • Windows ‒ XP、Vista、Win7、Win8、Win2008、Win10
  • Unix/X11 ‒ Linux、Sun Solaris、HP-UX、Compaq Tru64 UNIX、IBM AIX、SGI IRIX、FreeBSD、
    BSD/OS、和其他很多 X11 平台
  •   Macintosh ‒ Mac OS X
  • Embedded ‒ 有帧缓冲⽀持的嵌⼊式 Linux 平台,Windows CE  
  • Android

 0.3 Qt 版本&& 优点

虽然目前最新的QT版本是QT6,但是我这里使用的是QT5

  • 跨平台 ,⼏乎⽀持所有的平台;
  • 接⼝简单,容易上⼿ ,学习 QT 框架对学习其他框架有参考意义。
  • ⼀定程度上简化了内存回收机制
  • 开发效率⾼,能够快速的构建应⽤程序。
  • 有很好的社区氛围,市场份额在缓慢上升。
  • 可以进⾏嵌⼊式开发。

0.4 Qt 的应⽤场景

  • 主要: 桌⾯应⽤程序, 嵌⼊式系统

  • 次要: 移动应⽤程序

注: 嵌入式系统指的是日常使用的: 冰箱,洗衣机,路由器,投影仪...之类的
      这些设备里面就使用了嵌入式系统

0.5 QT成功案例

Linux 桌⾯环境 KDE


 0.6 Qt 的发展前景

  • Qt 是⼀个 强⼤且⼴泛应⽤于跨平台软件开发的框架 。它提供了丰富的⼯具和库,可⽤于开发⾼质量、 ⾼效率的图形⽤⼾界⾯(GUI)应⽤程序

1. 搭建 Qt 开发环境 

第一部分: c++编译器(gcc,cl.exe....不是visual studio)

第二部分: Qt SDK(软件安装包)

第三部分: Qt 集成开发环境(IDE)

  • Qt 官方提供的Qt creator(不需要额外的配置,适合初学者)
  • Visual Studio 功能更强,但是需要额外的配置更多
  • Eclipse 不推荐

注: 这里只安装一个QT SDK就行了

1.1 Qt SDK 的下载

官网: Index of /archive/qt

  • 注: 如果无法访问,则可以使用网盘链接: 链接:提取码bite

1.2 Qt SDK 的安装

这里建议在双击之前断网,否则需要我们注册 Qt 账号登录后才能进⼊下 ⼀步安装 

  • 其他的,就不断下一步,下一步就行了 

1.3 配置环境变量

  至于为什么要配置这个环境变量: 

  • 为了让操作系统/QT Creator工具,能够找到Qt SDK中提供的exe,也就是运行Qt 程序的时候,能够找到对应.dll 动态库

 2. 认识QT Creator

2.1 使⽤ Qt Creator 新建项⽬

  •  其实,一路next,next也行

2.2 认识新建项目

 2.2.1 main.cpp

2.2.2 widget.h

 2.2.3 widget.cpp

2.2.4 widget.ui

  • Qt中使用xml文件就是去描述程序界面是什么样的
  • 进一步的qmake会调用相关的工具,依据这个xml文件生成一些c++代码,从而把完整的界面构建出来

 2.2.5 临时文件

  • 在运行一次程序之后,就会在 项目并列的地方,多出一个"build-xxxx"目录
  • 这个目录里面就是该项目运行过程中,生成的一些临时文件

2.3. 第一个hello world

2.3.1 图形化

  • 刚才往界面上拖拽了一个QLabel控件,此时,ui文件的xml中就会多出来这一段代码
  • 进一步的qmake就会在编译项目的时候,基于这个内容,生成一段C++代码,通过这个C++代码构建出界面内容

2.3.2 纯代码

  • 一般通过代码来构造界面的时候,通常会把构造界面放到Widget/MainWindow的构造函数中
  • 这里的this指针,是给当前这个label对象,指定一个父对象(以后会说的对象树)
  • 在QT中的字符串和C++/C中的字符串是不一样的,当时C++/C的字符串不好用,所以QT为了字节的开发能变的顺畅,就自己发明了一套轮子,搞了一系列基础类,来支持QT的开发,包括但不限于
    字符串->QString 动态数组->QVector 链表->QList 字典->QMap
  • 在QString中也提供了 C风格字符串作为参数的构造函数,不显示构造QString,上述代码中,C风格字符串也会隐式构造成QString对象 
  • 每个标签都有一个同名的头文件,但有时候也会被其他头文件间接包含,
    比如: QString 对应的头文件,已经被很多Qt内置的其他类给间接包含了,因此一般不需要显示包含QString头文件

这里还有一个值得思考的点: 一个对象new出来了,但是却没有delete,这难道不会造成内存泄漏吗

  • ​​​​在上述代码中,Qt不会产生内存泄漏,label对象会在合适的时候被析构函数释放~~
  • 之所以能够把对象释放掉,主要是因为把这个对象挂到了对象树上了,交给Qt的对象树统一管理
  • 如果这个对象是在栈上创建的话,就有可能会存在一些"提前释放"的问题,此时就会导致对应的控件就在界面上不存在了
  • 推荐: 在堆上创建对象,并挂在对象树上

2.3.3 验证对象树会统一析构

  • 注: 上面少写了个delete
  •  自己实现label类,并继承QLabel,然后再自主实现析构函数
  • 则可以在输出日志中观察到 自己实现的析构函数被调用了,则对象树的确会统一析构
  • 这里使用qDebug进行输出日志(不建议使用cout),还有一个好处->可以进行统一关闭
    输出日志一般是在开发阶段,调试程序的时候使用

 2.4 快捷键

  • 注释:ctrl + /
  • 运⾏:ctrl + R
  • 编译:ctrl + B
  • 字体缩放:ctrl + ⿏标滑轮
  • 查找:ctrl + F
  • 整⾏移动:ctrl + shift + ⬆/⬇
  • 帮助⽂档:F1
  • ⾃动对⻬:ctrl + i
  • 同名之间的 .h 和 .cpp 的切换:F4
  • ⽣成函数声明的对应定义: alt + enter

2.5 使⽤帮助⽂档 

  • 光标放到要查询的类名/⽅法名上, 直接按 F1(推荐)
  • Qt Creator 左侧边栏中直接⽤⿏标单击 "帮助" 按钮
  • 找到 Qt Creator 的安装路径,在 "bin" ⽂件夹下找到 assistant.exe,双击打开;

2.6 Qt 中的命名规范

  • 类名:⾸字⺟⼤写,单词和单词之间⾸字⺟⼤写;MyClass  MyAdd

  • 函数名及变量名:⾸字⺟⼩写,单词和单词之间⾸字⺟⼤写;studentCount

2.7 Qt 窗⼝坐标体系

计算机中的坐标系和数学中的坐标系是不一样的,y轴是向下增长的

 


 

  •  对于嵌套窗口,其坐标是相对于父窗口来说的

3. 信号与槽

优点: 松散耦合   缺点: 效率较低

信号源: 由那个控件发出的信号

信号类型: 用户进行不同的操作,就可能会触发不同的信号

信号处理的方式: 槽(slot) -> 函数,这个函数的本质就是一种回调函数(callback)

Qt中可以使用connect这样的函数,把一个信号和一个槽关联起来,后续只要信号触发了,Qt就会自动执行槽函数

 而在Qt中,一定是先关联信号 和 槽 ,然后再触发这个信号,顺序不能颠倒否则信号就不知道如何处理

 3.1 connect函数

在 Qt 中, QObject 类提供了⼀个静态成员函数 connect() ,该函数专⻔⽤来关联指定的信号函数和槽 函数

  • connect(const QObject * sender,const char* signal,const QObject* receiver
    const char* method, Qt::ConnectionType type = Qt::AutoConnection)
  • sender: 描述当前信号是那个控件发出的
  • signal: 描述信号类型
  • receiver: 描述了那个控件负责处理
  • method: 描述了这个控件怎么处理(要处理信号的对象提供成员函数)

3.2 深度理解connect函数参数

  • 我们上面传信号和槽都是传递的函数指针,而在C++中是不允许使用2个不同指针类型,相互传参相互赋值的(函数传参,本质就是赋值)
  • 其实这个函数声明是以前旧版本的QT的connect函数声明,以前个信号参数传参,要搭配要给SIGNAL宏,给槽函数传参要搭配一个SLOT宏(这样做的目的是 将 传入参数 转成char*)
  • connect(button,SIGNAL(&QPuhsButton::clicked),this,SLOT(&Widget::close))

但是后来因为书写起来太麻烦了,在Qt5时进行了改进

  •  使用模板实现泛型编程,重载构造函数  
  •   此时connect函数就有一定的参数检查功能:参数1和参数2不匹配 or 参数3和参数4不匹配,
    都会编译出错
  • 则要求参数2必须是参数1的成员函数,参数4必须是参数3的成员函数

3.2 查看信号与槽

 自己平时的积累 + 查看文档

  •  QPushButton自己本身没有clicked信号,但是它继承了QAbstractButton
  • 在QAbstractButton中就有一个clicked点击信号
  • 注: 这个QAbstractButton又使继承QWidget

  •  我们写的widget在定义的时候就是继承QWidget的,而QWidget就有close这个关闭槽
  • 注: QWidget这个类又是继承自QObject类的

3.3 自定义槽

 3.3.1 纯代码

3.3.2 图形化

  • 使用图形化的方式创建,QTCreator 会直接给我们生成好一个函数on_pushButton_clicked
    
  • 在Qt中,除了通过connect来连接信号槽之外,还可以通过函数名字的方式自动连接

  •  Qt中调用这个函数的时候,就会触发上述自动连接信号槽的规则
  • 这个正是在自动生成的ui_widget.h中调用的

3.4 自定义信号(了解)

  • 自定义信号,本质就是一个函数,只需要声明就行了,而这个函数的定义,是Qt在编译过程中,自动生成的(我们无法干预)
  • 而作为信号参数,这个函数的返回值,必须是void的,有没有参数都是可以的,甚至可以支持重载
  • Qt内置的信号,不需要手动触发,而自定义信号,需要手动代码触发  emit mySignal();
  • 这里使用图形化方式创建一个按钮,在通过这个按钮发送 自定义信号
  • 发送信号的操作, 也可以在任意合适的代码中. 不一定非得在构造函数里

3.6 带参数的信号与槽

  •  带有参数的信号,要求信号的参数和槽的参数要一致

  • 类型,个数要满足要求(信号的参数个数要多于槽的参数个数)

3.7 额外说明

3.7.1 前置条件

  •  Qt 中如果要让某个类能够使用信号槽(可以在类中定义信号和槽函数),则必须要在类最开始的地方,写下Q_OBJECT
  • 将这个宏展开,会得到一大段代码,然后而这一大段代码又可以展开

 3.7.2 设计目的

  • 解耦,: 把触发 用户操作的控件 和 处理对应用户的操作逻辑 解耦合
  • 实现"多对多"效果
    一个信号,可以connect到多个槽函数上
    一个槽函数也可以被多个信号connect
  • 但是多对多的需求实际中并不常见,所以以后图形化开发框架都没有支持多对多

 3.7.3 disconnect断开连接

主动断开往往是把信号重新绑定到另一个槽函数上

  • 如果没有 disconnect, 就会构成 一个信号绑定了两个槽函数. 触发信号的时候, 两个槽函数都会执行

3.7.4 lambda表达式 

定义槽函数的时候,也是可以使用lambda表达式的,

  •  为了解决lambda访问作用域的问题,就需要引入变量捕捉的语法规则
  • lambda语法是c++11中引入的,对于Qt5及其更高版本,默认就是按照c++ 11来编译的
  • 如果使用Qt4或者更老的版本,就需要手动在.pro文件中加上C++的编译选项:CONFIG += c++11

4. 常用控件

 4.1 QWidget 核心属性

4.1.0 objectName 

4.1.1 enabled

API说明
isEnabled()
获取到控件的可⽤状态
setEnabled
设置控件是否可使⽤. true 表⽰可⽤, false 表⽰禁⽤

 4.1.2 geometry && window frame

geometry: x y width height

API
说明
geometry()
获取到控件的位置和尺⼨. 返回结果是⼀个 QRect, 包含了 x, y, width, height. 其
中 x, y 是左上⻆的坐标
setGeometry (QRect)
setGeometry (int x, int y,
int width, int height)
设置控件的位置和尺⼨. 可以直接设置⼀个 QRect, 也可以分四个属性单独设置.

 

  •  注意: setGeometry(QRect),使用这个函数可能会改变原来的控件的width 和 heiv

API
说明(以下API:  计算时包含 window frame)
x()
获取横坐标
y()
获取纵坐标
pos()
返回 QPoint 对象, ⾥⾯包含 x(), y(), setX(), setY() 等⽅法.
frameSize()
返回 QSize 对象, ⾥⾯包含 width(), height(), setWidth(), setHeight() 等⽅法.
frameGeometry()
返回 QRect 对象. QRect 相当于 QPoint 和 QSize 的结合体. 可以获取 x, y, width, size.
API
说明(以下API:  计算时不包含 window frame)
width()
获取宽度
height()
获取⾼度
size()
返回 QSize 对象, ⾥⾯包含 width(), height(), setWidth(), setHeight() 等⽅法.
rect()
返回 QRect 对象. QRect 相当于 QPoint 和 QSize 的结合体. 可以获取并设置 x,
y, width, size.
geometry()
返回 QRect 对象. QRect 相当于 QPoint 和 QSize 的结合体. 可以获取 x, y,
width, size
setGeometry()
直接设置窗⼝的位置和尺⼨. 可以设置 x, y, width, height, 或者 QRect 对象

4.1.3 windowTitie 

API说明
windowTitle()
获取到控件的窗⼝标题.
setWindowTitle(const QString& title)
设置控件的窗⼝标题

 4.1.4 windowlcon

API
说明
windowIcon()
获取到控件的窗⼝图标. 返回 QIcon 对象
setWindowIcon(const QIcon& icon )
设置控件的窗⼝图标.
通过 qrc 管理图⽚作为图标

 给Qt项目引入一个额外的xml文件(后缀名使用.qrc表示),在这个xml中把要使用的图片资源给导入进来,并且在xml中记录

Qt在编译项目的时候,就会根据qrc中描述的图片信息,找到图片内容,并且提取出图片的二进制数据,把这些二进制数据转换成C++代码,最终编译到exe里


 新建qrc文件

  • 注意 : 添加的⽂件必须是在 qrc ⽂件的同级⽬录, 或者同级⽬录的⼦⽬录中. 

 

  •  在引入了qrc机制之后,就可以直接用相对路径访问的这个图片
  • qrc机制主要解决2个问题:
    确保图片所在的路径在目标用户机器上存在
    确保图片不会被用户搞没了

4.1.5 windowOpacity 

API说明
windowOpacity()
获取到控件的不透明数值. 返回 float , 取值为 0.0 -> 1.0
其中 0.0 表⽰全透明,1.0 表⽰完全不透明
setWindowOpacity(float n)
设置控件的不透明数值.

  •  注意: 窗口的不透明度,变化并非是精确的,这主要和浮点数在内存中的存储有关

4.1.6 cursor

API
说明
cursor()
获取到当前 widget 的 cursor 属性, 返回 QCursor 对象.
当⿏标悬停在该 widget 上时, 就会显⽰出对应的形状
setCursor(const QCursor& cursor)
设置该 widget 光标的形状. 仅在⿏标停留在该 widget 上时⽣效.
QGuiApplication::setOverrideCursor(co
nst QCursor& cursor )
设置全局光标的形状. 对整个程序中的所有 widget 都会⽣效. 覆盖
上⾯的 setCursor 设置的内容.

 

  • QPixmap是一个位图对象 

4.1.7 font

API
说明
font()
获取当前 widget 的字体信息. 返回 QFont 对象
setFont(const QFont& font)
设置当前 widget 的字体信息

 关于 QFont

属性
说明
family
字体家族. ⽐如 "楷体", "宋体", "微软雅⿊" 等.
pointSize
字体⼤⼩
weight
字体粗细. 以数值⽅式表⽰粗细程度取值范围为 [0, 99], 数值越⼤, 越
bold
是否加粗. 设置为 true, 相当于 weight 为 75. 设置为 false 相当于 weight 为 50
italic
是否倾斜
underline
是否带有下划线
strikeOut
是否带有删除线

  •  也可以使用ui界面直接修改

4.1.8 tooltip(解释说明的意思)

API
说明
setToolTip
设置 toolTip. ⿏标悬停在该 widget 上时会有提⽰说明.
setToolTipDuring
设置 toolTip 提⽰的时间. 单位 ms. 时间到后 toolTip ⾃动消失

4.1.9 focusPolicy(设置控件获取到焦点)

设置控件获取到焦点的策略. ⽐如某个控件能否⽤⿏标选中或者能否通过 tab 键选中.
API
说明
focusPolicy()
获取该 widget 的 focusPolicy, 返回 Qt::FocusPolicy
setFocusPolicy(Qt::FocusPolicy policy )
设置 widget 的 focusPolicy.

 

  • Qt::NoFocus :控件不会接收键盘焦点
  • Qt::TabFocus :控件可以通过Tab键接收焦点
  • Qt::ClickFocus :控件在⿏标点击时接收焦点
  • Qt::StrongFocus :控件可以通过Tab键和⿏标点击接收焦点 (默认值)
  • Qt::WheelFocus : 类似于 Qt::StrongFocus , 同时控件也通过⿏标滚轮获取到焦点 (新增
    的选项, ⼀般很少使⽤)

  • ui界面上也可以直接更改 

4.1.10 styleSheet

通过 CSS 设置 widget 的样式.

  •  也可以在ui界面上右键,然后再添加编辑样式表,

  • 注意:这里的css样式别写错了,如果写错了Qt是不会报错的

4.2 按钮类 

4.2.1 Pushbutton(普通按钮)

API说明
text
按钮中的⽂本
icon
按钮中的图标
iconSize
按钮中图标的尺⼨
shortCut
按钮对应的快捷键
autoRepeat
按钮是否会重复触发. 当⿏标左键按住不放时,
如果设为 true, 则会持续产⽣⿏标点击事件;
如果设为 false, 则必须释放⿏标, 再次按下⿏标时才能产⽣点击事件.
(相当于游戏⼿柄上的 "连发" 效果)
autoRepeatDelay
重复触发的延时时间. 按住按钮多久之后, 开始重复触发.
 autoRepeatInterval
重复触发的周期.
  •  QAbstractButton 作为 QWidget 的⼦类, 当然也继承了 QWidget 的属性. 上⾯
    介绍的 QWidget ⾥的各种属性⽤法, 对于 QAbstractButton 同样适⽤


4.2.2 Radio Buttion(单选)  

API说明
checkable
是否能选中
checked
是否已经被选中. checkable 是 checked 的前提条件
autoExclusive
是否排他.
选中⼀个按钮之后是否会取消其他按钮的选中.
对于 QRadioButton 来说默认就是排他的


4.2.3 QButtonGroup(按钮组)

  • QButtonGroup表示: 每⼀组内部来控制排他, 但是组和组之间不能排他 

4.2.4 Check Box(多选)

 4.2.5 Tool Button(工具按钮)

QToolButton 的⼤部分功能, 和 QPushButton 是⼀致的. 但是 QToolButton 主要应⽤在⼯
具栏, 菜单等场景. 

4.3 显示

4.3.1 Lable(普通文本框)

属性
说明
text
QLabel 中的⽂本
textFormat
Qt::PlainText 纯⽂本
Qt::RichText 富⽂本(⽀持 html 标签)
Qt::MarkdownText markdown 格式
Qt::AutoText 根据⽂本内容⾃动决定⽂本格式
pixmap
QLabel 内部包含的图⽚
scaledContents
设为 true 表⽰内容⾃动拉伸填充 QLabel
设为 false 则不会⾃动拉伸
alignment
对⻬⽅式.
可以设置⽔平和垂直⽅向如何对⻬
wordWrap
设为 true 内部的⽂本会⾃动换⾏.
设为 false 则内部⽂本不会⾃动换⾏.
indent
设置⽂本缩进. ⽔平和垂直⽅向都⽣效
margin
内部⽂本和边框之间的边距.
不同于于 indent, 但是是上下左右四个⽅向都同时有效.
⽽ indent 最多只是两个⽅向有效(具体哪两个⽅向有效取决于 alignment )
openExternalLinks
是否允许打开⼀个外部的链接.
(当 QLabel ⽂本内容包含 url 的时候涉及到)
buddy
给 QLabel 关联⼀个 "伙伴" , 这样点击 QLabel 时就能激活对应的伙伴.
例如伙伴如果是⼀个 QCheckBox, 那么该 QCheckBox 就会被选中


  • 虽然 QPushButton 也可以通过设置图标的⽅式设置图⽚, 但是并⾮是⼀个好的选择. 更多的时候还是希望通过 QLabel 来作为⼀个 更单纯的显⽰图⽚ 的⽅式.

 上述的案例存在一个问题,用户在拉伸窗口时,图片的size并没有随之改变,我们需要引入事件来解决

Qt中,表示用户的操作,有两类概念:一个是信号,另一个是事件~~

 

  

  • 当用户拖拽窗口大小的时候,就会触发resize事件(resizeEvent)
  • 像resize这样的事件,是连续变化的,把窗口尺寸从A拖到B这个过程中,就会触发一系列的resizeEvent,然后就可以借助resizeEvent来完成上述的功能

  • 此处设置的缩进,即使文本换行了后续的行也会产生缩进,不仅仅是首行缩进

 

  • 在QT中,QLabel中写的文本,是可以指定"快捷键",但这里的快捷键的规则功能上,要比QPushButton要弱一点
  • 它表示快捷键的操作是 & 跟上一个字符来表示快捷键
    比如: &A => 通过键盘上的alt+a来触发
  • 绑定了伙伴关系之后,通过快捷键就可以选中对应的单选按钮/复选按钮

4.3.2 LCD Number(LCD电子数字)

QLCDNumer 是⼀个专⻔⽤来显⽰数字的控件. 类似于 "⽼式计算器" 的效果.  

属性
说明
intValue
QLCDNumber 显⽰的数字值(int).
value
QLCDNumber 显⽰的数字值(double). 和intValue 是联动的.
例如给 value 设为 1.5, intValue 的值就是 2.
另外,设置 value 和 intValue 的⽅法名字为 display , ⽽不是 setValue 或 者 setIntValue
digitCount
显⽰⼏位数字.
mode
数字显⽰形式.
1. QLCDNumber::Dec :⼗进制模式,显⽰常规的⼗进制数字。
2. QLCDNumber::Hex :⼗六进制模式,以⼗六进制格式显⽰数字。
3. QLCDNumber::Bin :⼆进制模式,以⼆进制格式显⽰数字。
4. QLCDNumber::Oct :⼋进制模式,以⼋进制格式显⽰数字
只有⼗进制的时候才能显⽰⼩数点后的内容
segmentStyle
设置显⽰⻛格.
1. QLCDNumber::Flat :平⾯的显⽰⻛格,数字呈现在⼀个平坦的表⾯上。
2. QLCDNumber::Outline :轮廓显⽰⻛格,数字具有清晰的轮廓和阴影效果。
3. QLCDNumber::Filled :填充显⽰⻛格,数字被填充颜⾊并与背景区分开
smallDecimalPoin
设置⽐较⼩的 ⼩数点.

关于定时器 

  •  在C++标准库中,没有提供定时器的实现,但Boost里面提供了对应的功能
  • 而在Qt中也封装了对应的定时器~~(结合了信号槽机制)
  • 通过QTimer这个类创建处理的对象,就会产生一个timeout这样的信号
  • 再结合connect,把这个timeout信号绑定到需要的槽函数中,就可以执行周期性的修改LCDNumber中的数字

  •  在Qt里面,界面中有一个专门的线程去负责维护更新(主线程->main函数所在的线程)
  • 而对于GUI来说,内部包含了很多的隐藏状态,Qt为了保证修改界面的过程中,线程安全是不会受影响的,所以Qt就禁止了其他线程直接修改界面
    ui->lcdNumer->display(value),形如这种操作,就是在修改界面
  • 对于Qt的槽函数来说,默认情况下,槽函数都是由主线程调用的,在槽函数中修改界面是没有任何问题的
    但要是自己创建了一个新线程,再修改界面就会出错,程序就会异常退出

4.3.3  ProgressBar(进度条)

属性说明
minimum
进度条最⼩值
maximum
进度条最⼤值
value
进度条当前值
alignment
⽂本在进度条中的对⻬⽅式
Qt::AlignLeft : 左对⻬
Qt::AlignRight : 右对⻬
Qt::AlignCenter : 居中对⻬
Qt::AlignJustify : 两端对⻬
textVisible
进度条的数字是否可⻅.
orientation
进度条的⽅向是⽔平还是垂直
invertAppearance
是否是朝反⽅向增⻓进度
textDirection
⽂本的朝向
format
展⽰的数字格式.
%p :表⽰进度的百分⽐(0-100)
%v :表⽰进度的数值(0-100)
%m :表⽰剩余时间(以毫秒为单位)
%t :表⽰总时间(以毫秒为单位)

  • 进度条的更新也是需要搭配定时器来完成的

 4.3.4 Calendar Widget(日历)

属性说明
selectDate
当前选中的⽇期
minimumDate
最⼩⽇期
maximumDate
最⼤⽇期
firstDayOfWeek
每周的第⼀天(也就是⽇历的第⼀列) 是周⼏
gridVisible
是否显⽰表格的边框
selectionMode
是否允许选择⽇期
navigationBarVisible
⽇历上⽅标题是否显⽰
horizontalHeaderFormat
⽇历上⽅标题显⽰的⽇期格式
verticalHeaderFormat
⽇历第⼀列显⽰的内容格式
dateEditEnabled
是否允许⽇期被编辑

重要信号
信号
说明
selectionChanged(const QDate&)
当选中的⽇期发⽣改变时发出
activated(const QDate&)
当双击⼀个有效的⽇期或者按下回⻋键时发出,
形参是⼀个QDate类型,保存了选中的⽇期
currentPageChanged(int, int)
当年份⽉份改变时发出,形参表⽰改变后的新年份和⽉份

4.4 输入类控件 

4.4.1 Line Edit(单行输入框)

属性说明
text
输⼊框中的⽂本
inputMask
输⼊内容格式约束
maxLength
最⼤⻓度
frame
是否添加边框
echoMode
显⽰⽅式.
QLineEdit::Normal :这是默认值,⽂本框会显⽰输⼊的⽂本。
QLineEdit::Password :在这种模式下,输⼊的字符会被隐藏,
通常⽤星号(*)或等号(=)代替。
QLineEdit::NoEcho :在这种模式下,⽂本框不会显⽰任何输⼊
的字符
cursorPosition
光标所在位置
alignment
⽂字对⻬⽅式, 设置⽔平和垂直⽅向的对⻬
dragEnabled
是否允许拖拽
readOnly
是否是只读的(不允许修改)
placeHolderText
当输⼊框内容为空的时候, 显⽰什么样的提⽰信息
clearButtonEnabled
是否会⾃动显⽰出 "清除按钮"

核⼼信号

属性
说明
void cursorPositionChanged(int old, int new)
当⿏标移动时发出此信号,old为先前的位置,new为新位置
void editingFinished()
当按返回或者回⻋键时,或者⾏编辑失去焦点时,发出此信号
void returnPressed()
当返回或回⻋键按下时发出此信号.
如果设置了验证器, 必须要验证通过, 才能触发
void selectionChanged()
当选中的⽂本改变时,发出此信号
void textChanged(const
QString &text)
当QLineEdit中的⽂本改变时,发出此信号,text是新的⽂本。
代码对⽂本的修改 能够 触发这个信号
void textEdited(const QString
&text))
当QLineEdit中的⽂本改变时,发出此信号,text是新的⽂本。
代码对⽂本的修改 不能 触发这个信号.

  • inputMask 只能进⾏简单的输⼊格式校验.
    实际开发中, 基于 正则表达式 的⽅式是更核⼼的⽅法

使⽤正则表达式验证输⼊框的数据
要求在输⼊框中输⼊⼀个合法的电话号码(1 开头, 11 位, 全都是数字). 如果验证不通过, 则确定按钮⽆法点击

 

  •  这里说明一下state validator(QString&,int &)函数的2个参数,
  • 第一个参数是要验证的字符串,参数类型是QString & 不是const QString&,所以这里我创建了一个临时对象
  • 第二个参数表示,如果这个字符串不符合规则,是从那个位置开始的

4.4.2 Text Edit(多行输入框)

QTextEdit 表⽰多⾏输⼊框. 也是⼀个富⽂本 & markdown 编辑器. 并且能在内容超出编辑框范围时⾃动提供滚动条

属性说明
markdown
输⼊框内持有的内容. ⽀持 markdown 格式. 能够⾃动的对markdown ⽂本进⾏
渲染成 html
html
输⼊框内持有的内容. 可以⽀持⼤部分 html 标签. 包括 img 和 table 等
placeHolderText
输⼊框为空时提⽰的内容.
readOnly
是否是只读
undoRedoEnable
是否开启 undo / redo 功能.
按下 ctrl + z 触发 undo
按下 ctrl + y 触发 redo
autoFormating
开启⾃动格式化.
tabstopWidth
按下缩进占多少空间
overwriteMode
是否开启覆盖写模式
acceptRichText
是否接收富⽂本内容
verticalScrollBarPolicy
垂直⽅向滚动条的出现策略
Qt::ScrollBarAsNeeded : 根据内容⾃动决定是否需要滚动条。这是默认值。
Qt::ScrollBarAlwaysOff : 总是关闭滚动条。
Qt::ScrollBarAlwaysOn : 总是显⽰滚动条。
horizontalScrollBarPolicy
⽔平⽅向滚动条的出现策略
Qt::ScrollBarAsNeeded : 根据内容⾃动决定是否需要滚动条。这是默认值。
Qt::ScrollBarAlwaysOff : 总是关闭滚动条。
Qt::ScrollBarAlwaysOn : 总是显⽰滚动条

核心信号

核心属性说明
textChanged()
⽂本内容改变时触发
selectionChanged()
选中范围改变时触发
cursorPositionChanged()
光标移动时触发
undoAvailable(bool)
可以进⾏ undo 操作时触发
redoAvailable(bool)
可以进⾏ redo 操作时触发
copyAvaiable(bool)
⽂本被选中/取消选中时触发

 4.4.3 Combo Box(下拉选择框)

属性说明
currentText
当前选中的⽂本
currentIndex
当前选中的条⽬下标
从 0 开始计算. 如果当前没有条⽬被选中, 值为 -1
editable
是否允许修改
设为 true 时, QComboBox 的⾏为就⾮常接近 QLineEdit , 也可以设置 validator
iconSize
下拉框图标 (⼩三⻆) 的⼤⼩
maxCount
最多允许有多少个条⽬

核⼼⽅法

⽅法
说明
addItem(const QString&)
添加⼀个条⽬
currentIndex()
获取当前条⽬的下标
从 0 开始计算. 如果当前没有条⽬被选中, 值为 -1
currentText()
获取当前条⽬的⽂本内容

核⼼信号
方法说明
activated(int)
activated(const QString & text)
当⽤⼾选择了⼀个选项时发出.
这个时候相当于⽤⼾点开下拉框, 并且⿏标划过某个选项.
此时还没有确认做出选择
currentIndexChanged(int)
currentIndexChanged(const QString
& text)
当前选项改变时发出.
此时⽤⼾已经明确的选择了⼀个选项.
⽤⼾操作或者通过程序操作都会触发这个信号
editTextChanged(const QString &
text)
当编辑框中的⽂本改变时发出
(editable 为 true 时有效)

  •  下拉框里的条目,一般都是从网络/文件中读取的
  • QString::fromStdString(s);// 把std::string 转换成QString
  • s.toStdString();//把QString转换成std::string

4.4.4 Spin Box(微调框) 

属性说明
value
存储的数值
singleStep
每次调整的 "步⻓". 按下⼀次按钮数据变化多少
displayInteger
数字的进制. 例如 displayInteger 设为 10, 则是按照 10 进制表⽰. 设为 2 则为 2 进制表⽰
minimum
最⼩值
maximum
最⼤值
suffix
后缀
prefix
前缀
wrapping
是否允许换⾏
frame
是否带边框
alignment
⽂字对⻬⽅式.
readOnly
是否允许修改
buttonSymbol
按钮上的图标.
UpDownArrows 上下箭头形式
PlusMinus 加减号形式
NoButtons 没有按钮
accelerated (加速的)
按下按钮时是否为快速调整模式
correctionMode
输⼊有误时如何修正.
QAbstractSpinBox::CorrectToPreviousValue : 如果⽤⼾输⼊了⼀个⽆效的值(例如,在只能显⽰正整数的SpinBox中输⼊了负数),那么SpinBox会恢复为上⼀个有效值。例如,如果SpinBox的初始值是1,⽤⼾
输⼊了-1(⽆效),然后SpinBox会恢复为1。
QAbstractSpinBox::CorrectToNearestValue : 如果⽤⼾输⼊了⼀个 ⽆效的值,SpinBox会恢复为最接近的有效值。例如,如果SpinBox的初始值是1,⽤⼾输⼊了-1(⽆效),那么SpinBox会恢复为0
keyboardTrack
是否开启键盘跟踪.
设为 true, 每次在输⼊框输⼊⼀个数字, 都会触发⼀次 valueChanged() 和
textChanged() 信号.
设为 false, 只有在最终按下 enter 或者输⼊框失去焦点, 才会触发
valueChanged() 和 textChanged() 信号.
核⼼信号
信号
说明
textChanged(QString)
微调框的⽂本发⽣改变时会触发. 参数 QString 带有 前缀 和 后缀.
valueChanged(int)
微调框的⽂本发⽣改变时会触发.
参数 int, 表⽰当前的数值

4.4.5 Date Edit & Time Edit  (日期&时间微调框)

这⼏个控件⽤法⾮常相似, 这里以 QDateTimeEdit 为例进⾏介绍
属性说明
dateTime
时间⽇期的值. 形如 2000/1/1 0:00:00
date
单纯⽇期的值. 形如 2001/1/1
time
单纯时间的值. 形如 0:00:00
displayFormat
时间⽇期格式. 形如 yyyy/M/d H:mm
y 表⽰年份
M 表⽰⽉份
d 表⽰⽇期
H 表⽰⼩时
m 表⽰分钟
s 表⽰秒
注意: 这⾥的格式化符号的含义, 不要记忆. 不同语⾔/库的设定规则
是存在差异的. ⼀定是⽤的时候再去查
minimumDateTime
最⼩时间⽇期
maximumDateTime
最⼤时间⽇期
timeSpec
Qt::LocalTime :显⽰本地时间。
Qt::UTC :显⽰协调世界时(UTC)。
Qt::OffsetFromUTC :显⽰相对于UTC的偏移量(时差)
  •  UTC 时间是⼀个基于原⼦钟的标准时间
  • 如我们使⽤的北京时间, 位于 "东⼋区", 就需要在 UTC 时间基础上 +8 个⼩时的时差

 核⼼信号

信号
说明
dateChanged(QDate)
⽇期改变时触发.
timeChanged(QTime)
时间改变时触发.
dateTimeChanged(QDateTime)
时间⽇期任意⼀个改变时触发.

 

4.4.6 Dial(旋转按钮)

属性说明
value
持有的数值.
minimum
最⼩值
maximum
最⼤值
singleStep
按下⽅向键的时候改变的步⻓
pageStep
按下 pageUp / pageDown 的时候改变的步⻓
sliderPosition
界⾯上旋钮显⽰的 初始位置
tracking
外观是否会跟踪数值变化.
默认值为 true. ⼀般不需要修改.
wrapping
是否允许循环调整.
即数值如果超过最⼤值, 是否允许回到最⼩值.
(调整过程能否 "套圈")
notchesVisible
是否显⽰ 刻度线
notchTarget
刻度线之间的相对位置.
数字越⼤, 刻度线越稀疏

核心信号

属性说明
valueChanged(int)
数值改变时触发
rangeChanged(int, int)
范围变化时触发

4.4.7 Slider(滑动条) 

属性
说明
value
持有的数值.
minimum
最⼩值
maximum
最⼤值
singleStep
按下⽅向键的时候改变的步⻓
pageStep
按下 pageUp / pageDown 的时候改变的步⻓
sliderPosition
滑动条显⽰的 初始位置
tracking
外观是否会跟踪数值变化.
默认值为 true. ⼀般不需要修改
orientation
滑动条的⽅向是⽔平还是垂直
invertedAppearance
是否要翻转滑动条的⽅向
tickPosition
刻度的位置
tickInterval
刻度的密集程度

核⼼信号

属性
说明
valueChanged(int)
数值改变时触发
rangeChanged(int, int)
范围变化时触发

  • 通过这些设置,就可以让滑动条控制拉伸窗口的大小 

  •  也可以通过QShortcut这里个类实现快捷键,并connect槽函数

4.5 多元素控件

  • QListWidget QListView 列表
  • QTableWidget QTableView 表格
  • QTreeWidget QTreeView 树形

4.5.0 xxWidget vs xxView是什么区别

  • xxView是MVC结构的一种典型实现,MVC是软件开发中,非常经典的软件结构组织形式
    M model数据,V view 视图(界面),C controller控制器 数据和视图之间的业务流程

  • xxView只是负责实现了视图,不负责数据如何存储表示,更不负责数据和视图之间的交互

  • 而xxWidget是基于xxView封装而来的,同时吧model和controller都帮我们实现好了
    可以直接使用,它提供了功能很方便的api,让我们直接使用

 4.5.1 List Widget(纵向列表)

属性说明
currentRow
当前被选中的是第⼏⾏
count
⼀共有多少⾏
sortingEnabled
是否允许排序
isWrapping
是否允许换⾏
itemAlignment
元素的对⻬⽅式
selectRectVisible
被选中的元素矩形是否可⻅
spacing
元素之间的间隔

 核⼼⽅法

⽅法
说明
addItem(const QString& label)
addItem(QListWidgetItem * item)
列表中添加元素
currentItem()
 返回 QListWidgetItem* 表⽰当前选中的元素
setCurrentItem(QListWidgetItem* item)
设置选中哪个元素
setCurrentRow(int row)
设置选中第⼏⾏的元素
insertItem(const QString& label, int row)
insertItem(QListWidgetItem * item, int row)
在指定的位置插⼊元素
item(int row)
返回 QListWidgetItem* 表⽰第 row ⾏的元素
takeItem(int row)
删除指定⾏的元素, 返回 QListWidgetItem* 表⽰是哪个元素被删
除了

核心信号

方法说明
currentItemChanged(QListWidgetItem*
current, QListWidgetItem* old)
选中不同元素时会触发. 参数是当前选中的元素和之前选中的元素
currentRowChanged(int)
选中不同元素时会触发. 参数是当前选中元素的⾏数.
itemClicked(QListWidgetItem* item)
点击某个元素时触发
itemDoubleClicked(QListWidgetItem* item)
双击某个元素时触发
itemEntered(QListWidgetItem* item)
⿏标进⼊元素时触发

  •  对于添加条目,可以直接通过图形化界面的方式

 

  •  使用QListWidget时,记得包含头文件<QListWidget>

 4.5.2 Table Widget(表单)

TableWidget控件相当于二维ListWidget

属性说明
item(int row, int column)
根据⾏数列数获取指定的 QTableWidgetItem*
setItem(int row, int column,
QTableWidget*)
根据⾏数列数设置表格中的元素
currentItem()
返回被选中的元素 QTableWidgetItem*
currentRow()
返回被选中元素是第⼏⾏
currentColumn()
返回被选中元素是第⼏列
row(QTableWidgetItem* )
获取指定 item 是第⼏⾏
column(QTableWidgetItem* )
获取指定 item 是第⼏列
rowCount()
获取⾏数
columnCount()
获取列数
insertRow(int row)
在第 row ⾏处插⼊新⾏
insertColumn(int column)
在第 column 列插⼊新列
removeRow(int row)
删除第 row ⾏

 removeColumn(int column)

删除第 column 列
setHorizontalHeaderItem(int column, QTableWidget*)
设置指定列的表头
setVerticalHeaderItem(int row, QTableWidget*)
设置指定⾏的表头

 核⼼信号

信号
说明
cellClicked(int row, int column)
点击单元格时触发
cellDoubleClicked(int row, int
column)
双击单元格时触发
cellEntered(int row, int column)
⿏标进⼊单元格时触发
currentCellChanged(int row, int column, int previousRow, int previousColumn)
选中不同单元格时触发
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{ 
    ui->setupUi(this);
    ui->lineEdit->setPlaceholderText("请输入一列名");
    ui->lineEdit_2->setPlaceholderText("请输入一行名");
    // 初始化表单
    // 创建 3 行
    ui->tableWidget->insertRow(0);
    ui->tableWidget->insertRow(1);
    ui->tableWidget->insertRow(2);

    // 给 3 行设定行名
    ui->tableWidget->setVerticalHeaderItem(0, new QTableWidgetItem("NO.1"));
    ui->tableWidget->setVerticalHeaderItem(1, new QTableWidgetItem("NO.2"));
    ui->tableWidget->setVerticalHeaderItem(2, new QTableWidgetItem("NO.3"));

    // 创建 3 列
    ui->tableWidget->insertColumn(0);
    ui->tableWidget->insertColumn(1);
    ui->tableWidget->insertColumn(2);

    // 给 3 列设定列名
    ui->tableWidget->setHorizontalHeaderItem(0, new QTableWidgetItem("学号"));
    ui->tableWidget->setHorizontalHeaderItem(1, new QTableWidgetItem("姓名"));
    ui->tableWidget->setHorizontalHeaderItem(2, new QTableWidgetItem("年龄"));

    // 设置初始数据
    ui->tableWidget->setItem(0, 0, new QTableWidgetItem("1001"));
    ui->tableWidget->setItem(0, 1, new QTableWidgetItem("张三"));
    ui->tableWidget->setItem(0, 2, new QTableWidgetItem("20"));

    ui->tableWidget->setItem(1, 0, new QTableWidgetItem("1002"));
    ui->tableWidget->setItem(1, 1, new QTableWidgetItem("李四"));
    ui->tableWidget->setItem(1, 2, new QTableWidgetItem("21"));

    ui->tableWidget->setItem(2, 0, new QTableWidgetItem("1003"));
    ui->tableWidget->setItem(2, 1, new QTableWidgetItem("王五"));
    ui->tableWidget->setItem(2, 2, new QTableWidgetItem("19"));

}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_pushButton_addrow_clicked()
{
   int row = ui->tableWidget->rowCount();
   ui->tableWidget->insertRow(row);
   const QString& name = ui->lineEdit_2->text();
   ui->tableWidget->setVerticalHeaderItem(row,new QTableWidgetItem(name));
}

void Widget::on_pushButton_addcolum_clicked()
{
    int col = ui->tableWidget->columnCount();
    ui->tableWidget->insertColumn(col);
    const QString& name = ui->lineEdit->text();
    ui->tableWidget->setHorizontalHeaderItem(col,new QTableWidgetItem(name));
}

void Widget::on_pushButton_delrow_clicked()
{
    int row = ui->tableWidget->currentRow();
    ui->tableWidget->removeRow(row);
}

void Widget::on_pushButton_delcolum_clicked()
{
    int cur = ui->tableWidget->currentColumn();
    ui->tableWidget->removeColumn(cur);
}

4.5.3 Tree Widget (树状形节点表单)

属性说明
clear
清空所有⼦节点
addTopLevelItem(QTreeWidgetItem* item)
新增顶层节点
topLevelItem(int index)
获取指定下标的顶层节点.
topLevelItemCount()
获取顶层节点个数
indexOfTopLevelItem(QTreeWidgetItem*
item)
查询指定节点是顶层节点中的下标
takeTopLevelItem(int index)
删除指定的顶层节点. 返回 QTreeWidgetItem* 表⽰被删除
的元素
currentItem()
获取到当前选中的节点, 返回 QTreeWidgetItem*
setCurrentItem(QTreeWidgetItem* item)
选中指定节点
setExpanded(bool)
展开/关闭节点
setHeaderLabel(const QString& text)
设置 TreeWidget 的 header 名称.

核心方法

方法说明
addChild(QTreeWidgetItem* child)
新增⼦节点
childCount()
⼦节点的个数
child(int index)
获取指定下标的⼦节点. 返回 QTreeWidgetItem*
takeChild(int index)
删除对应下标的⼦节点
removeChild(QTreeWidgetItem*
child)
删除对应的⼦节点
parent()
获取该元素的⽗节点

核⼼信号

信号说明
currentItemChanged(QTreeWidgetItem*
current, QTreeWidgetItem* old)
切换选中元素时触发
itemClicked(QTreeWidgetItem* item, int col)
点击元素时触发
itemDoubleClicked(QTreeWidgetItem* item, int col)
双击元素时触发
itemEntered(QTreeWidgetItem* item, int col)
⿏标进⼊时触发
itemExpanded(QTreeWidgetItem* item)
元素被展开时触发
itemCollapsend(QTreeWidgetItem* item)
元素被折叠时触发
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{ 
    ui->setupUi(this);
    ui->treeWidget->setHeaderLabel("动物");

    QTreeWidgetItem* item1 = new QTreeWidgetItem();
    item1->setText(0, "猫");
    ui->treeWidget->addTopLevelItem(item1);//添加顶层节点

    QTreeWidgetItem* item2 = new QTreeWidgetItem();
    item2->setText(0, "狗");
    ui->treeWidget->addTopLevelItem(item2);//添加顶层节点

    QTreeWidgetItem* item3 = new QTreeWidgetItem();
    item3->setText(0, "鸟");
    ui->treeWidget->addTopLevelItem(item3);//添加顶层节点
}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_pushButton_clicked()
{
    const QString& text = ui->lineEdit->text();
    if(text.isEmpty()){
        return;
    }
    // 添加到顶层节点中
    QTreeWidgetItem* item = new QTreeWidgetItem();
    item->setText(0,text);
    ui->treeWidget->addTopLevelItem(item);
}

void Widget::on_pushButton_2_clicked()
{
     const QString& text = ui->lineEdit->text();
     if (text.isEmpty()) {
        return;
     }
     // 获取到当前选中的节点
     QTreeWidgetItem* currentItem = ui->treeWidget->currentItem();
     if (currentItem == NULL) {
        return;
     }
     // 构造新的 item
     QTreeWidgetItem* newItem = new QTreeWidgetItem();
     newItem->setText(0, text);
     // 添加 item 到选中节点
     currentItem->addChild(newItem);
     // 展开父节点
     currentItem->setExpanded(true);
}

void Widget::on_pushButton_3_clicked()
{
    QTreeWidgetItem* cur = ui->treeWidget->currentItem();
    if(cur == NULL){
        return;
    }
    // 获取当前节点的父节点
    QTreeWidgetItem* parent = cur->parent();
    if(parent == NULL){
        // 顶层节点
        // 查询指定节点是顶层节点中的下标
        int index = ui->treeWidget->indexOfTopLevelItem(cur);
        ui->treeWidget->takeTopLevelItem(index);
    }
    else{
        // 非顶层节点
        parent->removeChild(cur);
    }
}

  •  QTreeWidget控件虽然是树形结构,但是这个树形结构,没有体现出根节点,
    是从根节点的下一次子节点开始计算的
  • 针对顶层节点来说,这里也是一个类似于"List"这样的结构

 4.6 容器类控件

4.6.1 Group Box(控件组)

属性
说明
title
分组框的标题
alignment
分组框内部内容的对⻬⽅式
flat
是否是 "扁平" 模式
checkable
是否可选择.
设为 true, 则在 title 前⽅会多出⼀个可勾选的部分
checked
描述分组框的选择状态 (前提是 checkable 为 true)

4.6.2 Tab Widget(多页面) 

属性说明
tabPosition
标签⻚所在的位置.
North 上⽅
South 下⽅
West 左侧
East 右侧
currentIndex
当前选中了第⼏个标签⻚ (从 0 开始计算)
currentTabText
当前选中的标签⻚的⽂本
currentTabName
当前选中的标签⻚的名字
currentTabIcon
当前选中的标签⻚的图标
currentTabToolTip
当前选中的标签⻚的提⽰信息
tabsCloseable
标签⻚是否可以关闭
movable
标签⻚是否可以移动

核⼼信号
属性
说明
currentChanged(int)
在标签⻚发⽣切换时触发, 参数为被点击的选项卡编号
tabBarClicked(int)
在点击选项卡的标签条的时候触发. 参数为被点击的选项卡编号
tabBarDoubleClicked(int)
在双击选项卡的标签条的时候触发. 参数为被点击的选项卡编号.
tabCloseRequest(int)
在标签⻚关闭时触发. 参数为被关闭的选项卡编号. ​​​​​​
  • Qt 中使⽤ ⽗⼦关系 决定控件的相对位置

 4.7 布局控件

4.7.1 QVBoxLayout(垂直布局)

Layout 只是⽤于界⾯布局, 并没有提供信号 

属性
说明
layoutLeftMargin
左侧边距
layoutRightMargin
右侧边距
layoutTopMargin
上⽅边距
layoutBottomMargin
下⽅边距
layoutSpacing
相邻元素之间的间距

  • 界⾯上的按钮就存在于布局管理器中. 随着窗⼝尺⼨变化⽽发⽣改变  

 

  • 界面上的按钮不会随窗口尺寸变化而发生改变 
  • 通过 Qt Designer 创建的布局管理器, 其实是先创建了⼀个 widget, 设置过 geometry 属性
    的. 再把这个 layout 设置到这个 widget 中.
  • 实际上, ⼀个 widget 只能包含⼀个 layout.

4.7.2 QHBoxLayout(水平布局) 

Layout 只是⽤于界⾯布局, 并没有提供信号 

属性
说明
layoutLeftMargin
左侧边距
layoutRightMargin
右侧边距
layoutTopMargin
上⽅边距
layoutBottomMargin
下⽅边距
layoutSpacing
相邻元素之间的间距

  • 界⾯上的按钮就存在于布局管理器中. 随着窗⼝尺⼨变化⽽发⽣改变 

  • 布局控件是可以嵌套的所以 结合 QHBoxLayout QVBoxLayout , 就可以做出各种复杂的界⾯了 

4.7.3 QGridLayout(网格布局) 

属性说明
layoutLeftMargin
左侧边距
layoutRightMargin
右侧边距
layoutTopMargin
上⽅边距
layoutBottomMargin
下⽅边距
layoutHorizontalSpacing
相邻元素之间⽔平⽅向的间距
layoutVerticalSpacing
相邻元素之间垂直⽅向的间距
layoutRowStretch
⾏⽅向的拉伸系数
layoutColumnStretch
列⽅向的拉伸系数

  •  使⽤ addWidget 添加控件到布局管理器中. 但是添加的同时会指定两个坐标. 表⽰放在第⼏⾏, 第⼏列
  • 任意调整⾏列, 即可看到不同的效果

  • 注意: 如果要设置垂直方法的拉伸 直接 setRowStretch 效果不明显, 因为每个按钮的⾼度是固定的. 需要
  • 把按钮的垂直⽅向的 sizePolicy 属性设置为 QSizePolicy::Expanding 尽可能填
    充满布局管理器, 才能看到效果
    btn1->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

 4.7.4 QFormLayout(表单布局)

属于是 QGridLayout 的特殊情况, 专⻔⽤于实现 两列表单的布局

这种表单布局多⽤于让⽤⼾填写信息的场景. 左侧列为提⽰, 右侧列为输⼊框 

4.7.5 Spacer(空白布局) 

使⽤布局管理器的时候, 可能需要 在控件之间, 添加⼀段空⽩ . 就可以使⽤ QSpacerItem 来表⽰.
属性说明
width
宽度
height
⾼度
hData
⽔平⽅向的 sizePolicy
QSizePolicy::Ignored : 忽略控件的尺⼨,不对布局产⽣影响。
QSizePolicy::Minimum : 控件的最⼩尺⼨为固定值,布局时不会超过该值。
QSizePolicy::Maximum : 控件的最⼤尺⼨为固定值,布局时不会⼩于该值。
QSizePolicy::Preferred : 控件的理想尺⼨为固定值,布局时会尽量接近该
值。
QSizePolicy::Expanding : 控件的尺⼨可以根据空间调整,尽可能占据更多空
间。
QSizePolicy::Shrinking : 控件的尺⼨可以根据空间调整,尽可能缩⼩以适应
空间。
vData
垂直⽅向的 sizePolicy
选项同上.

  • 调整 QSpacerItem 不同的尺⼨, 即可看到不同的间距 

5. QT窗口

Qt 窗⼝ 是通过 QMainWindow 类 来实现的。

  • 菜单栏(menu bar)
  • ⼯具栏(tool bars)
  • 浮动窗⼝(铆 接部件)(dock widgets)
  • 状态栏(status bar)
  • 中⼼部件(central widget)

5.1 菜单栏

⼀个主窗⼝最多只有⼀个菜单栏

5.1.1 创建菜单栏&&菜单&&菜单项 

  • 这里的菜单项和后面的工具栏的工具是同一个类,都是QAction 

 5.1.2 添加快捷键 && 链接信号槽 

  •  菜单项点击的时候会触发triggered信号,和前面那个信号类似

5.1.3 创建子菜单

  • 就是在菜单中嵌套另一个菜单,就叫做子菜单

5.1.4 设置菜单项图标

  •  如果给菜单也加上图标的话,就会把菜单的text覆盖

5.1.5 关于正确创建QMenuBar类 

  •  如果我们之前创建的项目,没有勾选ui文件,此时这2种代码都是正确的
  • 但是如果勾选了自动生成ui文件,那么第2种代码就会引起内存泄漏,因为Qt已经自动生成了一个QMenuBar(在ui文件中,各个类的结构中可以看到),同时后面的QStatusBar也是一样的问题

5.2 ⼯具栏

⼯具栏是应⽤程序中集成各种功能实现快捷键使⽤的⼀个区域 

5.2.1 创建工具栏 

  •  工具栏是可以有多个,并且可以像浮动窗口一样浮动和移动的

5.2.2 设置工具栏停靠位置 

  •  Qt::LeftToolBarArea 停靠在左侧
  • Qt::RightToolBarArea 停靠在右侧
  • Qt::TopToolBarArea 停靠在顶部
  • Qt::BottomToolBarArea 停靠在底部
  • Qt::AllToolBarAreas 以上四个位置都可停靠
  • Qt中很多枚举类型值,都不建议死记,建议不清楚的时候查查文档

5.3 状态栏

状态栏是应⽤程序中输出简要信息的区域

5.3.1 创建工具栏 

5.4 滑动窗口 

5.4.1 创建滑动窗口

  • 浮动窗口内部, 添加一些其他的控件,不能直接给这个浮动窗口添加子控件, 而是需要创建出一个单独的 QWidget, 把要添加的控件加入到 QWidget 中

  • 然后再把这个 QWidget 设置到 dockWidget 中.

5.5 对话框

5.5.1 创建对话框

  • QDialog不同于其他控件,此处QDialog每次按下按钮,都会创建一个新的QDialog对象
  • 而一个程序运行过程中,可能会无数次触发点击这个按钮,就会产生无数个这样的对象
    不好好处理,就会出现内存泄漏的问题,

  • Qt为了方便我们使用,就封装了一层,在实际使用的时候,只要给dialog设置上下面这个属性
    就会在关闭的时候自动进行delete(这个属于Qt内置的功能)
  • dialog->setAttribute(Qt::WA_DeleteOnClose);

5.5.2 自定义对话框 

  •  想要自定义对话框,就需要继承自QDialog创建类,这里是通过代码自定义的

  • 这个操作会创建出一个ui文件以及对应的类 
  • 通过图形化的方式创建会比代码创建的更快一些,因为会自动生成ui文件

5.5.3 模态与非模态

  • dialog->show() 非模态: 弹出对话框的时候,用户可以操作父窗口 
  • dialog->exec() 模态: 弹出对话框的时候,用户无法操作父窗口

  • Qt 提供了多种可复⽤的对话框类型,即 Qt 标准对话框。Qt 标准对话框全部继承于 QDialog类 

 5.5.4 QMessageBox(消息对话框)

Question
⽤于正常操作过程中的提问
Information
⽤于报告正常运⾏信息
Warning
⽤于报告⾮关键错误
Critical
⽤于报告严重错误

 

  •  QMessageBox 使用场景更多的是模态的.

 

  •  也可以通过QMessageBox中的静态成员函数,快速生成消息对话框

 5.5.5 QColorDialog(调色板对话框)

  •  直接调用QColorDialog静态成员函数生成对象是最快的

5.5.6  QFileDialog(文件对话框)

  • 此处的打开/保存这里的功能都是需要额外去实现的,并不是直接一保存就保存好了 

5.5.7 QInputDialog(输入对话框) 

5.5.8 QFontDialog(字体对话框) 

6.系统相关

6.1 事件

事件是应⽤程序内部或者外部产⽣的事情或者动作的统称

信号槽 : 用户进行的各项操作,就可能会产生出信号,可以给某个信号指定槽函数,当信号触发时,就能够自动的执行到对应的槽函数

事件: 用户进行的各种操作,也会产生事件,程序员同样可以给事件关联上处理函数(处理的逻辑),当事件触发的时候,就能够执行到对应的代码

总结:信号槽就是对于事件的进一步封装,事件是信号槽的底层机制

6.1.0 为什么会出现事件

  •  在实际Qt开发程序的过程中,绝大部分和用户之间进行的交互都是通过"信号槽"来完成的

  • 但是在有些特殊情况下,信号槽不一定能搞定(某个用户的动作行为,Qt没有提供对应的信号)

  • 此时就需要通过重写事件处理函数的形式,来手动处理事件的响应逻辑

  • 让当前的类,重写某个事件处理函数,这里用到的是"多态"机制,创建子类,继承自Qt中已有的类
    再在子类中重写父类的事件处理函数
    ,后续事件触发的过程中,就会通过多态这样的机制,执行到我们自己写的子类函数中

6.1.1 QMouseEvent(鼠标事件)

#ifndef LABEL_H
#define LABEL_H

#include <QWidget>
#include <QLabel>
#include <QMouseEvent>
class Label : public QLabel
{
    Q_OBJECT
public:
    Label(QWidget* parent);
    void mousePressEvent(QMouseEvent *event);// 按下
    void mouseReleaseEvent(QMouseEvent *event);// 释放
    void mouseDoubleClickEvent(QMouseEvent *event);// 双击
};

#endif // LABEL_H
#include "label.h"
#include <QDebug>
Label::Label(QWidget* parent) : QLabel(parent)
{
    ;
}

void Label::mousePressEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton){
        //qDebug() << "按下左键";
        this->setText("按下左键");
    }
    else if(event->button() == Qt::RightButton){
        qDebug() << "按下右键";
    }
}

void Label::mouseReleaseEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton){
        qDebug() << "释放左键";
    }
    else if(event->button() == Qt::RightButton){
        qDebug() << "释放右键";
    }
}

void Label::mouseDoubleClickEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton){
        qDebug() << "双击左键";
    }
    else if(event->button() == Qt::RightButton){
        qDebug() << "双击右键";
    }
}

  • 先在ui界面中创建label控件,再新创建一个文件,继承QLabel
  • 注意:这里需要再ui界面中把这个控件提升为我们自己写的类
  • 这里是针对QLabel重写的事件,自然也只能在label控件中看到效果

  • 这里是在widget中重写的事件,则这个大窗口都会有效果  
  • Qt为了保证程序的流畅性,默认情况下不会对鼠标移动进行追踪,鼠标移动的时候不会调用
    mouseMoveEvent,除非显示告诉Qt要追踪鼠标位置

6.1.2 QWheelEvent(鼠标滚轮事件)  

6.1.3 QKeyEvent(键盘事件) 

 6.1.4 QTimerEvent(时间事件)

  • 此处的timerId类似于linux中的文件描述符
  • QTimer的背后是QTimerEvent定时器事件进行支持的,所以要实现定时器,通常使用QTimer

6.1.5 QMoveEvent(窗口移动事件) 

6.1.6 QResizeEvent(窗口尺寸事件) 

6.2 文件

6.2.1 QFile类的各种操作

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QPlainTextEdit>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    void test_read();
    void test_write();
private:
    Ui::MainWindow *ui;
    QPlainTextEdit* edit;// 纯文件控件
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFileDialog>
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // 获取到菜单栏
    QMenuBar* menuBar = this->menuBar();

    // 添加菜单
    QMenu* menu = new QMenu("文件");
    menuBar->addMenu(menu);

    // 添加菜单项
    QAction* action1 = new QAction("打开");
    QAction* action2 = new QAction("保存");
    menu->addAction(action1);
    menu->addAction(action2);

    // 指定一个输入框
    edit = new QPlainTextEdit();
    QFont font;
    font.setPixelSize(20);
    edit->setFont(font);

    // 添加中心控件
    this->setCentralWidget(edit);

    // 链接信号槽
    connect(action1,&QAction::triggered,this,&MainWindow::test_read);
    connect(action2,&QAction::triggered,this,&MainWindow::test_write);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::test_read()
{
    // step1: 先弹出"打开文件" 对话框,让用户选择打开哪个文件
    QString path = QFileDialog::getOpenFileName(this);

    // step2: 把文件名显示到状态栏中
    QStatusBar* statusBar = this->statusBar();
    statusBar->showMessage(path);

    // step3: 根据用户选择的路径,构建一个QFile对象,并打开文件
    QFile file(path);
    bool ret = file.open(QFile::ReadOnly);// 只读
    if(!ret){
        statusBar->showMessage(path+"打开文件失败");
    }

    // step4: 读取文件
    QString text = file.readAll();

    // step5: 关闭文件
    file.close();

    // step6: 将读取到的内容设置到输入框中
    edit->setPlainText(text);

}

void MainWindow::test_write()
{
    // step1: 先弹出"保存文件" 对话框,让用户选择打开哪个文件
    QString path = QFileDialog::getSaveFileName(this);

    // step2: 把文件名显示到状态栏中
    QStatusBar* statusBar = this->statusBar();
    statusBar->showMessage(path);

    // step3: 根据用户选择的路径,构建一个QFile对象,并打开文件
    QFile file(path);
    bool ret = file.open(QFile::WriteOnly);// 只写
    if(!ret){
        statusBar->showMessage(path+"打开文件失败");
    }

    // step4: 写文件
    const QString& text = edit->toPlainText();
    file.write(text.toUtf8());

    // step5: 关闭文件
    file.close();

}


  •  在Qt 中提供的这一套文件操作,使用起来还是非常简单的

6.2.2 QFileInfo(文件相关属性) 

 6.3 线程

6.3.1 QThread

6.3.2 QMutex

 

  •  这里创建了2个线程,一个线程对num循环5k次,由于没加锁导致结果不是1w

  •  这里把锁加上就不会出现各个线程相互竞争的问题了

6.3.3 QMutexLocker 

 

  • 因为上面的锁很容易忘记释放,忘记unlock,在逻辑复杂的情况下
  • Qt中也有一个对互斥锁进行封装的类->QMutexLocker,类似与std::mutex智能指针 
  • C++11 也引入了std::lock_guard

6.3.4 其他补充说明

条件变量:QWaitCondition

信号量:QSemaphore

读写锁:QReadLocker、QWriteLocker、QReadWriteLock

  • 这里就暂不介绍了,这里类和API用法和Linux中的类似,就是对系统函数/接口的封装,

  • 要用到的时候,再查查文档

6.4 网路

  •  为了能够引入头文件,这里需要添加Network

6.4.1 UDP协议的回显交互

#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
#include <QNetworkDatagram>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    // step1: 创建套接字对象
    sock = new QUdpSocket(this);
    this->setWindowTitle("服务器");

    // step2: 连接信号槽
    connect(sock,&QUdpSocket::readyRead,this,&Widget::processRequest);

    // step3: 绑定端口
    bool ret = sock->bind(QHostAddress::Any,9090);// 任意ip
    if(!ret){
        QMessageBox::critical(this,"服务器启动出错",sock->errorString());
        return;
    }
}

Widget::~Widget()
{
    delete ui;
}

void Widget::processRequest()
{
    // step1: 读取请求并解析
    const QNetworkDatagram& requestDatagram = sock->receiveDatagram();
    QString request = requestDatagram.data();

    // step2: 根据请求计算响应(由于是回显服务器,响应不需要计算,就是请求本身)
    QString response = process(request);

    // step3: 把响应写回客户端
    QNetworkDatagram responseDatagram(response.toUtf8(),requestDatagram.senderAddress(),requestDatagram.senderPort());
    sock->writeDatagram(responseDatagram);

    // 把这次交互的信息, 显示到界面上.
    QString log = "[" + requestDatagram.senderAddress().toString() + ":" + QString::number(requestDatagram.senderPort())
            + "] req: " + request + ", resp: " + response;
    ui->listWidget->addItem(log);
}

QString Widget::process(const QString &request)
{
    return request;
}

  • 这是Udp_server.cpp文件

#include "widget.h"
#include "ui_widget.h"
#include <QNetworkDatagram>
// 定义2个常量,描述服务器的IP 和 端口
const QString& SERVER_IP = "127.0.0.1";
const quint16 SERVER_PORT = 9090;

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    // step1: 创建套接字对象
    socket = new QUdpSocket(this);
    this->setWindowTitle("客户端");

    // step2: 连接信号槽
    connect(socket,&QUdpSocket::readyRead,this,&Widget::processResponse);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_pushButton_clicked()
{
    // 1.获取到输入框的内容
    const QString& text = ui->lineEdit->text();
    // 2.构造UDP的请求数据
    QNetworkDatagram requestDatagram(text.toUtf8(),QHostAddress(SERVER_IP),SERVER_PORT);
    // 3.发送请求数据
    socket->writeDatagram(requestDatagram);
    // 4.把发送的请求也添加到列表框中
    ui->listWidget->addItem("客户端说: " + text);
    // 5. 把输入框的内容也清空一下
    ui->lineEdit->setText("");
}

void Widget::processResponse()
{


    // 通过这个函数来处理收到的响应
    // 1.读取到响应数据
    const QNetworkDatagram& responseDatagram = socket->receiveDatagram();
    QString response = responseDatagram.data();
    // 2. 把响应数据显示到界面上
    ui->listWidget->addItem("服务器回应: " +response);
}
  •  这是udp_client.cpp文件

6.4.2 TCP协议的回显交互

#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
#include <QTcpSocket>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //1. 创建QTcpServer实例
    tcpServer = new QTcpServer(this);
    this->setWindowTitle("服务端");

    // 2.连接信号槽
    connect(tcpServer,&QTcpServer::newConnection,this,&Widget::processConnection);

    // 3. 绑定并监听端口号
    bool ret = tcpServer->listen(QHostAddress::Any,9090);
    if(!ret){
        QMessageBox::critical(this,"服务器启动失败!",tcpServer->errorString());
        return;
    }
}

Widget::~Widget()
{
    delete ui;
}

void Widget::processConnection()
{
    // 1. 通过 tcpServer 拿到一个 socket 对象, 通过这个对象来和客户端进行通信.
    QTcpSocket* clientSocket = tcpServer->nextPendingConnection();
    QString log = "[" + clientSocket->peerAddress().toString() + ":" + QString::number(clientSocket->peerPort()) + "] 客户端上线!";
    ui->listWidget->addItem(log);

    // 2. 通过信号槽, 来处理客户端发来请求的情况.
    connect(clientSocket, &QTcpSocket::readyRead, this, [=]() {
        // a) 读取出请求数据. 此处 readAll 返回的是 QByteArray, 通过赋值转成 QString
        QString request = clientSocket->readAll();
        // b) 根据请求处理响应
        const QString& response = process(request);
        // c) 把响应写回到客户端
        clientSocket->write(response.toUtf8());
        // d) 把上述信息记录到日志中.
        QString log = "[" + clientSocket->peerAddress().toString() + ":" + QString::number(clientSocket->peerPort()) + "] "
                + " req: " + request + ", resp: " + response;
        ui->listWidget->addItem(log);
    });

    // 3. 通过信号槽, 来处理客户端断开连接的情况.
    connect(clientSocket, &QTcpSocket::disconnected, this, [=]() {
        // a) 把断开连接的信息通过日志显示出来.
        QString log = "[" + clientSocket->peerAddress().toString() + ":" + QString::number(clientSocket->peerPort()) + "] 客户端下线!";
        ui->listWidget->addItem(log);
        // b) 手动释放 clientSocket. 直接使用 delete 是下策, 使用 deleteLater 更加合适的.
        // delete clientSocket;
        clientSocket->deleteLater();
    });
}

// 此处写的是回显服务器.
QString Widget::process(const QString request)
{
    return request;
}
  •  这是tcp_server.cpp文件

#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    // 1. 设置窗口标题
    this->setWindowTitle("客户端");
    // 2. 创建 socket 对象的实例
    socket = new QTcpSocket(this);
    // 3. 和服务器建立连接.
    socket->connectToHost("127.0.0.1", 9090);
    // 4. 连接信号槽, 处理响应
    connect(socket, &QTcpSocket::readyRead, this, [=]() {
        // a) 读取出响应内容
        QString response = socket->readAll();
        // b) 把响应内容显示到界面上.
        ui->listWidget->addItem("服务器说: " + response);
    });
    // 5. 等待连接建立的结果. 确认是否连接成功.
    bool ret = socket->waitForConnected();
    if (!ret) {
        QMessageBox::critical(this, "连接服务器出错", socket->errorString());
        exit(1);
    }
}

Widget::~Widget()
{
    delete ui;
}


void Widget::on_pushButton_clicked()
{
    // 1. 获取到输入框中的内容
    const QString& text = ui->lineEdit->text();
    // 2. 发送数据给服务器.
    socket->write(text.toUtf8());
    // 3. 把发的消息显示到界面上.
    ui->listWidget->addItem("客户端说: " + text);
    // 4. 清空输入框的内容.
    ui->lineEdit->setText("");
}
  •  这是tcp_client.cpp文件

6.4.3 HTPP协议

7. QSS

Qt中的QSS和前端中的CSS类似,也是通过设置样式美化界面

7.1 纯代码引入 

7.2 qrc机制引入 

7.3 ui界面中引入(推荐) 

7.4 子控件

 查阅文档: Qt Style Sheets Reference

  •  记不住就多查查

8. 绘画 

画图相关的操作,一般不会放到QWidget的构造函数中调用执行,而是Qt提供了要给paintEvet事件处理函数,在这里进行调用,和它对应的是QPaintEvent事件

  • QPainter: 提供一系列的绘画方法,实现绘画动作的
  • QPaintDevice: 画板,其实QWidget也是QPaintDevice的子类
  • QPen: 画笔
  • QBrush; 画刷(填充时的属性)
  • 25
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《Qt 5 开发及实例(第4)陆文周pdf》是一本介绍Qt开发的技术书籍。本书侧重讲解Qt开发的实践操作,适合想要学习Qt开发的初学者或者已经有一定基础的开发人员。 本书涵盖了Qt开发的各方面,包括了Qt的基础知识、界面设计、信号与槽机制、多线程编程、绘图与图像处理、网络编程等内容。通过这些内容,读者可以学习到Qt开发的核心知识和技术。 此外,本书的每一章都会有相应的实例演示,帮助读者理解Qt开发的具体应用场景。通过这些实例,读者可以学习到如何使用Qt开发实际的应用程序。本书配套的源代码可以帮助读者更好地理解书中的内容以及进行学习和实践。 总的来说,本书内容丰富、实用性强,适合Qt初学者和有一定基础的开发人员学习和参考。读者可以通过本书学习到Qt开发的核心知识和技术,并通过实例演示了解如何应用到实际的项目中。 ### 回答2: 《Qt 5 开发及实例》是一本关于Qt 5开发的书籍,作者是陆文周。这本书是第四,内容相比前几有了更多的新内容和实例。 在这本书中,作者从Qt的基本概念开始,逐步深入介绍了Qt的各个方面。读者可以通过学习这本书,全面了解Qt的使用方法和开发技巧,学会使用Qt构建高质量的跨平台应用程序。 这本书的第一部分介绍了Qt的基础知识,包括Qt的安装和配置、Qt Creator的使用、Qt的基本组件和对象模型等。此外,还详细介绍了Qt的信号与槽机制、事件处理等内容,帮助读者深入理解Qt的工作原理。 第二部分是关于Qt的核心模块,包括Qt的基本控件、布局管理器、绘图和渲染、多语言支持等内容。读者将学习如何使用这些模块来构建用户友好的应用程序。 第三部分则介绍了Qt的高级应用,包括多线程编程、网络编程、数据库编程、XML解析和Web服务等。作者通过实例展示了这些高级应用的使用方法,并提供了实用的开发技巧。 总的来说,这本书是一本非常实用的Qt开发指南,适合Qt初学者和有经验的开发者学习使用。如果你正在学习Qt,或者需要使用Qt开发跨平台应用程序,这本书将是你的不二之选。 ### 回答3: 《Qt 5开发及实例(第4)陆文周pdf》是一本介绍Qt 5开发的书籍,它包含了Qt的基础知识、图形界面、网络通信、多线程编程等内容,可以帮助读者快速入门Qt 5的开发。 本书采用了较为简洁明了的语言,结合大量的实例代码和图片,方便读者理解和掌握Qt 5的各个方面。书中还提供了大量的实际案例,包括制作音乐播放器、邮件客户端、画图软件等,这些实例可以帮助读者进一步掌握Qt 5的应用。 此外,本书还涉及了Qt 5的新特性,如支持移动开发Qt Quick、支持3D绘图的Qt 3D等,让读者了解到Qt 5的最新进展。加上本书附带的源代码、电子书等资源,对于想要学习Qt 5开发的读者来说,这本书是一本非常不错的参考材料。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值