Qt(跨平台的C++ GUI应用程序开发框架)
一 Qt的概述
1 Qt的历史发展
1)1991年Haavard Nord和Eirik Chambe-Eng合作编写最初的Qt
2)1994年创立TrollTech(奇趣科技公司)
3)2005年Qt4.0发布
4)2008年诺基亚收购了奇趣科技
5)2009年源代码开放
6)2012年诺基亚将Qt业务出售给Digia公司
7)2013年Qt5.0发布
8)2014年Digia成立子公司The Qt Company
www.qt.io
2 Qt5.4安装和配置
1)下载Qt安装包
qt-opensource-linux-x64-5.4.1.run//64位
qt-opensource-linux-x86-5.4.1.run//32位
2)运行安装程序,根据提示默认安装在主目录
./qt-opensource-linux-x64-android-5.4.1.run
3)配置环境变量
思路:将QT相关可执行程序所在路径添加到PATH环境变量中
home/tarena/Qt5.4.1/5.4/gcc_64/bin
/home/tarena/Qt5.4.1/Tools/QtCreator/bin
sudo vi /etc/environment
PATH="/home/tarena/Qt5.4.1/Tools/QtCreator/bin:/home/tarena/Qt5.4.1/5.4/gcc_64/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games"
4)重启系统,测试
tarena@ubuntu:~$ qmake -v //可以看到Qt版本
tarena@ubuntu:~$ qtcreator //可以进入Qt的IDE
问题:QT运行时依赖libgstreamer和openGL,如果没有需要单独安装
在线安装:
sudo apt-get install libgstreamer0.10-0
sudo apt-get install libgstreamer-plugins-base0.10-0
sudo apt-get install libgl1-mesa-dev
练习:检查自己开发环境,有问题尽快解决;如果没有问题“assistant”进入qt帮助手册随便看看
3 Qt相关工具介绍
1)assistant(Qt助手)
2)qmake(Qt构建器)
3)designer(Qt设计师)
4)uic(Qt转换器)
5)moc(元对象编译器)
6)rcc(资源编译器)
7)qtcreator(Qt创造器)
…
4 Qt助手的使用
eg:QApplication/QLabel
1)先看第一句话,了解该类的主要功能,如果看不懂,可以点击“more”查看详细说明.
2)接着往下看,了解头文件,构建选项,继承关系
3)Properties(成员变量)
4)Public Functions(公有的成员函数)
5)Reimplemented Public Functions(公有的虚函数)
6)Public Slots(槽函数)//Qt中语法扩展
class QXX{
public slots:
void slot_func(…);//槽函数
};
7)Signals(信号函数)//Qt中语法扩展
class QXX{
signals:
void signal_func(…);//信号函数
};
8)Static Public Members(静态成员)
9)Reimplemented Protected Functions(保护的虚函数)
10)Detailed Description(详细描述)
二 第一个Qt程序
1 创建工程目录
mkdir Hello
2 进入工程目录,编写源程序(cpp)
cd Hello
vi main.cpp
3 执行“qmake -project”,生成"Hello.pro"的工程文件
vi Hello.pro
//表示将来要连接和widgets模块对应的头文件、库文件
QT += widgets
4 执行"qmake",根据工程文件生成编译链接脚本Makefile
5 执行“make”完成编译和链接
注:如果代码有错误,修改之后再次执行make即可,一般3、4两步不需要重复执行.
6 运行测试
./Hello
三 Qt字符串(QString)和字符编码
1 常见编码
1)linux中默认utf-8
2)window中默认GBK
3)qt内部默认unicode
注:Qt5中使用“const char*”表示的中文字符串构造QString对象时,默认会使用fromUtf8()转换为unicode编码,可以正常显示.
2 编码转换(QTextCodec)
//char buf[]
QByteArray encodedString = “中文的GBK编码字符串”;
//1)创建GBK编码对象
QTextCodec *codec = QTextCodec::codecForName(“GBK”);
//2)将GBK编码字符串转换为Unicode编码
QString string = codec->toUnicode(encodedString);
练习:创建Qt应用程序,里面包含一个标签(QLabel)和一个按钮(QPushButton),标签显示文本“我是标签”,按钮显示文本“我是按钮”
1)用vi编写程序,构建6步,结果可以正常显示
2)通过vi底行命令修改编码方式为"gbk",再次make,结果中文乱码
:set fileencoding=gbk
3)通过QTextCodec进行编码转换,再次make,结果又可以正确显示.
四 父窗口(容器窗口)
1 创建图形控件可以指定父窗口,让其停靠在父窗口上面;如果没有指定父窗口则飘在外面形成独立窗体。
2 常用表示父窗口的类
1)QWidget
2)QMainWindow(主窗口)
3)QDialog(对话框)
注:QWidget和它的所有子类都可以用于父窗口,但是常用的父窗口类只有上面三个。
注:当父窗口对象销毁时,上面停靠的控件(对象)将自动被销毁,如果new的控件(对象),不显式delete也不会内存泄漏。
3 QWidget中两个常用函数
1)调整大小
resize(int w,int h);
2)调整位置
move(int x,int y);
回顾:
1 Qt概述
Qt4.x、Qt5.x
2 第一个Qt程序
1)创建工程目录
2)编写源码(cpp)
3)qmake -project//.pro QT+=widgets
4)qmake //Makefile
5)make
make clean/make distclean
6)测试
3 Qt字符串(QString)和字符编码
QTextCodec* codec=QTextCodec::codecForName(“GBK”);
QString str = codec->toUnicode(“中文”);
4 父窗口
QWidget
QMainWindow
QDialog
resize()/move()
今天:
一 信号和槽
1 概念
信号和槽中Qt自行定义的一种通信机制,实现对象之间数据交互.
2 定义
class XX:public QObject{
Q_OBJECT //moc编译器
public slots:
void slot_func(…);//槽
signals:
void signal_func(…);//信号
};
注:槽函数可以连接到某个对象的信号上,通过信号触发槽的执行;槽函数也可以当做普通成员直接调用.
注:信号函数只需声明,不能定义.
3 信号和槽连接
QObject::connect(
const QObject* sender,
const char * signal,
const QObject* receiver,
const char * method);
功能:建立信号和槽的连接
参数:
sender:信号的发送对象
signal:信号函数
receiver:信号的接收对象
method:槽函数
注:
SIGNAL(clicked(void));//将信号转换为const char*
SLOT(close(void));//将槽转换为const char*
案例:创建Qt应用程序,包含一个label和button,实现点击按钮关闭标签的功能
4 信号和槽连接时语法要求
1)信号和槽参数要一致
QObject::connect(A,SIGNAL(sigfunc(int)),
B,SLOT(slotfunc(int)));//ok
QObject::connect(A,SIGNAL(sigfunc(int)),
B,SLOT(slotfunc(int,int)));//error
2)可以带有缺省参数
QObject::connect(A,SIGNAL(sigfunc(int)),
B,SLOT(slotfunc(int,int=0)));//ok
3)信号函数的参数可以多于槽函数,多于参数将被忽略
QObject::connect(A,SIGNAL(sigfunc(int)),
B,SLOT(slotfunc(void)));//ok
4)一个信号可以同时连接到多个槽函数(一对多)
QObject::connect(A,SIGNAL(sigfunc(int)),
B1,SLOT(slotfunc1(int)));//ok
QObject::connect(A,SIGNAL(sigfunc(int)),
B2,SLOT(slotfunc2(int)));//ok
注:当A发送信号后,B1和B2的槽函数都将被执行,但是执行顺序不确定.
5)多个信号可以连接到一个槽函数(多对一)
QObject::connect(A1,SIGNAL(sigfunc1(int)),
B,SLOT(slotfunc(int)));//ok
QObject::connect(A2,SIGNAL(sigfunc2(int)),
B,SLOT(slotfunc(int)));//ok
注:无论A1还是A2发送信号,B的槽函数都将被执行
6)两个信号可以直接连接(信号级联)//了解
QObject::connect(A1,SIGNAL(sigfunc1(int)),
A2,SIGNAL(sigfunc2(int)));//ok
注:当A1对象发送信号时,A2对象的信号也将随之发送
案例:事件同步,滑块和选值框保持同步运行
1)QSlider滑块
//构造函数
QSlider(水平/垂直,父窗口);
//设置滑块滑动范围的函数
void setRange(int min,int max);
//滑动滑动时发送的信号
void valueChanged(int value)[singals]
//设置滑块位置
void setValue(int)[slots]
2)QSpinBox选值框(微调框)
//构造函数
QSpinBox(父窗口);
//设置选值框数值变化范围的函数
void setRange(int min,int max);
//选值框数值改变时发送的信号
void valueChanged(int value)[singals]
//设置选值框当前数值
void setValue(int)[slots]
二 面向对象的Qt编程
1 基于对象Qt编程//Qt功能受到限制,不推荐
2 面向对象的Qt编程
案例:加法计算器
思路:
class CalculatorDialog:public QDialog{
Q_OBJECT //moc
public:
CalculatorDialog(void){
//界面初始化
//信号和槽连接
}
public slots:
void 使能等号按钮槽函数(){}
void 计算和显示结果槽函数(){}
private:
QLineEdit,QLabel,QPushButton
};
int main(int argc,char** argv){
QApplication app(argc,argv);
CalculatorDialog calc;
calc.show();
return app.exec();
}
回顾:
1 信号和槽
1)不同对象之间通信方法
2)信号和槽连接
QObject::connect(
信号发送对象,SIGNAL(信号函数(参数)),
信号接收对象,SLOT(槽函数(参数)));
2 面向对象的Qt编程
今天:
一 Qt设计师(designer)
案例:使用qt设计,重构加法计算器
1 创建工程目录
mkdir Calculator2
2 进入工程目录,输入“designer”启动设计师
1)在新建窗体界面选择模板
“Dialog Without Button”
2)在设计师界面中完成“计算器”界面设计
–》从“widget Box”中找到所用图形控件拖拽到父窗口上
Label、LineEdit、PushButton
–》设置父窗口和每个控件属性
父窗口:
objectName(对象名):CalculatorDialog
windowTitle(窗口标题):加法计算器
font(字体):点大小(20)
左操作数:
objectName:m_editX
alignment:水平(AlignRight)
右操作数:
objectName:m_editY
alignment:水平(AlignRight)
显式结果:
objectName:m_editZ
alignment:水平(AlignRight)
readOnly(只读):勾选√
加号:
objectName:m_label
text:"+"
等号按钮:
objectName:m_button
enabled:去掉勾选√
text:"="
注:styleSheet(样式表):设置背景图片、各种颜色
–》调整每个控件大小和位置
方法1:鼠标拖拽
方法2:键盘,ctrl/shift+方向键
方法3:设置geometry属性,位置(x,y)/大小(宽度,高度)
方法4:使用布局器自动调整//推荐
–》窗体->预览
–》保存(ctrl+s),指定文件名“CalculatorDialog.ui”
–》关闭,最终得到一个“.ui”文件
3 将“.ui(xml)”转换为".h(c++)"
uic CalculatorDialog.ui -o ui_CalculatorDialog.h
ui_CalculatorDialog.h:
class Ui_CalculatorDialog{
public:
图形控件声明;
void setupUi(){
//界面初始化
}
};
namespace Ui{
class CalculatorDialog
:public Ui_CalculatorDialog{};
}
Ui::CalculatorDialog<=等价=>Ui_CalculatorDialog
使用ui_CalculatorDialog.h文件方法:
方法1:继承,参考Calculator2
class myClass:public Ui::CalculatorDialog{
//将界面中代码继承过来直接使用
};
方法2:组合,参考Calculator2_2
class myClass{
public:
myClass(){
ui = new Ui::CalculatorDialog;
ui->界面中代码
}
Ui::CalculatorDialog* ui;
};
4 编码、构建、测试…
案例:登录对话框
1 创建工程 Login
2 进入工程目录,通过设计师完成界面设计
1)拖拽使用控件 Label、LineEdit、ButtonBox
2)设置属性
父窗口:
objectName:LoginDialog
font:点大小(18)
windowTitle:登录
Label:
Text:用户名、密码
LineEdit:
m_usernameEdit(用户名输入控件)
m_passwordEdit(密码输入控件)
echoMode:password
ButtonBox:
objectName:m_btnBox
layoutDirection:RightToLeft
3)通过布局器调整大小和位置
4)保存,LoginDialog.ui
3 将.ui文件转换为.h文件
uic LoginDialog.ui -o ui_LoginDialog.h
4 编码、构建、测试…
二 Qt创造器(qtcreator)
《案例》使用qtcreator再次重构加法计算器
1 任意目录执行"qtcreator"进入Qt创造器界面
2 在欢迎模式下,点击“new Project”创建工程
1)选择模板
Application->Qt Widgets Application
2)项目介绍和位置
指定工程名字:Calculator3
指定所在路径:/home/tarena/qt/day03
注:将来会在指定路径下创建和工程名字一致的工程目录
3)Kit Selection(工具配置,默认即可)
4)类信息
选择基类(父窗口):QDialog
指定类名:CalculatorDialog
注:将来会根据类的名字生成对应源文件
CalculatorDialog.h
CalculatorDialog.cpp
CalculatorDialog.ui
5)项目管理(忽略)
6)完成,默认切换到编辑模式
3 双击".ui"进入设计模式,完成界面设计
1)从“widget Box”中找到所用图形控件拖拽到父窗口上
Label、LineEdit、PushButton
2)设置父窗口和每个控件属性
父窗口:
objectName(对象名):CalculatorDialog
注:父窗口对象名使用默认的,不要修改
windowTitle(窗口标题):加法计算器
font(字体):点大小(20)
左操作数:
objectName:m_editX
alignment:水平(AlignRight)
右操作数:
objectName:m_editY
alignment:水平(AlignRight)
显式结果:
objectName:m_editZ
alignment:水平(AlignRight)
readOnly(只读):勾选√
加号:
objectName:m_label
text:"+"
等号按钮:
objectName:m_button
enabled:去掉勾选√
text:"="
3)调整每个控件大小和位置
方法1:鼠标拖拽
方法2:键盘,ctrl/shift+方向键
方法3:设置geometry属性,位置(x,y)/大小(宽度,高度)
方法4:使用布局器自动调整//推荐
4)运行(ctrl+r)查看效果
4 编码、构建、测试…
回顾:
1 Qt的设计师
xx.ui(xml)–uic–>ui_xx.h(C++)
ui_xx.h:
class Ui_xx{
public:
图形控件声明;
void setupUi(){
界面初始化操作
}
};
namespace Ui{
class xx:public Ui_xx{};
}
使用方法:
1)继承
2)组合
2 Qt的创造器(IDE)
============================
今天:
一 资源和图像
1 资源编译器(rcc)
1)创建资源脚本(.qrc)
vi test.qrc
0.jpg
2)将资源脚本中描述的图片转换为C++的源文件
rcc test.qrc -o qrc_test.cpp
2 绘图事件
1)当应用程序开始运行或者窗口改变时,绘图事件将自动被触发,也可以调用“update()”来触发.
2)当绘图事件被触发后,对应的事件处理函数将被执行
void paintEvent(QPaintEvent*)[virtual];
3)绘图事件函数是虚函数,如果希望绘图事件触发完成自定义图像绘制,可以在自己的子类中重写该虚函数,然后通过“QPainter”完成自定义图像绘制。
3 Qt二维图形引擎QPainter
QPainter painter(this);
painter.drawImage(QRect,QImage);
QRect:描述矩形区域
QImage:描述图片对象
案例:图图秀
1)使用qtcreator创建工程:ShowPics
2)类信息:ShowPicsDialog
3)设计界面
–》Frame(显式框架)
objectName:m_fmImage
sizePolicy:垂直策略(Expanding)
frameShape:box
–》上一张(m_btnPrev)
–》下一张(m_btnNext)
4)添加资源文本
–》添加新文件:Qt->Qt Resource File
–》指定资源文件名:showpics.qrc
–》完成,默认切换到资源编辑界面
–》将ftp下载images目录拷贝工程目录下
–》添加-》添加前缀
“/new/prefix1”修改为“/”
–》添加-》添加文件
选择images目录下10个图片打开即可
二 目录和定时器
1 目录(QDir)
1)创建目录对象
QDir dir(const QString& path);
path:表示要访问的路径
绝对路径:
“/home/user/Documents”
“C:/Documents and Settings”
相对路径:
“images/landscape.png”
2)遍历目录
QStringList entryList(Filters filters)
filters:过滤器,指定要访问的内容
QDir::Dirs //子目录
QDir::Files //普通文件
QDir::NoDotAndDotDot //不包括".","…"
2 定时器
1)定时器事件 //参考Timer1
void timerEvent(QTimerEvent*)
–>开启定时器
//每隔interval毫秒触发一个定时器事件,返回ID
int startTimer(int interval);
–>关闭定时器
void killTimer(int id);
2)定时器类(QTimer)//参考Timer2
QTimer timer;
timer.start(int interval);//开启定时器
//每次定时器到时,发送信号timeout
connect(&timer,SIGNAL(timeout()),
this,SLOT(mySlot()));
timer.stop();//关闭定时器
案例:摇奖机
1)工程名:Ernie
2)类名:ErinieDialog
3)界面设计
–》m_fmPhoto
sizePolicy:垂直策略(expanding)
frameShape:box
–》m_btnStart
三 鼠标和键盘操作
1 鼠标事件 QMouseEvent
//鼠标按下时执行的事件处理函数
void mousePressEvent(QMouseEvent* event);
//鼠标抬起时执行的事件处理函数
void mouseReleaseEvent(QMouseEvent*);
//鼠标移动时执行的事件处理函数
void mouseMoveEvent(QMouseEvent*);
//鼠标双击时执行的事件处理函数
void mouseDoubleClickEvent(QMouseEvent*);
//判断是否为鼠标左键按下
if(event->button() == Qt::LeftButton){
…
}
QRect(坐标(x,y),大小(w,h));
QPoint(坐标(x,y));
QSize(大小(w,h));
案例:实现用鼠标拖拽“标签”移动
工程名:Mouse
类名:MouseDialog
设置label背景颜色:
1)stylesheet(样式表)
添加颜色:background-color
2)调色板
autoFillBackground:勾选√
palette:点击继承->改变调色板->选择颜色
2 键盘事件 QKeyEvent*
//按键按下执行的事件处理函数
void keyPressEvent(QKeyEvent*);
//按键抬起时执行的事件处理
void keyReleaseEvent(QKeyEvent*);
案例:实现用方向键控制“标签”移动
1)工程名:Keyboard
2)类名:KeyboardDialog
练习:总结QT中类
后面:数据库(Sqlite),多线程(QThread),网络(network)
回顾:
1 资源和图像
1)资源编译器rcc
2)绘图事件 paintEvent()/QPainter
2 目录和定时器
1)目录操作 QDir
2)定时器 timerEvent()/QTimer
3 鼠标和键盘
1)鼠标事件 QMouseEvent
mousePressEvent(),mouseReleaseEvent()
mouseMoveEvent(),mouseDoubleClickEvent()
2)键盘事件 QKeyEvent
keyPressEvent()/keyReleaseEvent()
今天:
一 Qt数据库(Sqlite)
1 简介
1)什么是数据库
数据库是指以一定方式存储在一起,能为多个用户共享,具有尽可能小的冗余特性,是与应用程序彼此独立的数据集合。
2)相关名词
DB 数据库(database)
DBMS 数据库管理系统
DBA 数据库管理员
RDB 关系式数据库//普遍
3)常见的数据库
商业数据库:
–》甲骨文Oracle,市场占有率50%
–》IBM的DB2,市场占有率20%
–》微软的Sqlserver,市场占有率15%
非商业数据库:
–》Sun的MySQL
–》开源的Sqlite,轻量级嵌入式数据库
4)数据库操作语言(SQL)
2 Sqlite数据库
1)安装Sqlite
sudo apt-get install sqlite3//在线安装
2)测试
在终端执行“sqlite3”,正常可进入Sqlite命令行操作界面,在其中输入指令实现对数据库的操作。
SQLite version 3.11.0 2016-02-15 17:29:24
sqlite> …
注:在“sqlite>”提示界面,可以输入两种指令,一种以".“开头,实现对sqlite配置和显式格式相关配置;另一种指令是“sql语句”,实现数据的增删改查操作,以”;"结束。
3 sqlite自身配置和格式相关的指令
1).help: 查看帮助信息
2).quit和.exit:退出sqlite,回到终端
3).database:查看数据库名字和对应的文件名
4).table:查看数据库包含数据表的名字
5).schema:查看数据表创建时详细信息
6).mode MODE:设置数据显示模式
MODE可以是“tab/column/list/…”
7).header on:显示表头
8).nullvalue “NULL”:空白位置显示“NULL”
注:"ctrl+L"可以清屏
注:"SELECT * FROM company;"查看company数据表的全部内容
注:可以将和显示先关的指令写入配置文件,每次sqlite运行时将会自动加载
vi /home/tarena/.sqliterc
.mode tab
.header on
.nullvalue “NULL”
4 在命令行使用“sql语句”实现对数据库操作 //重点
1)创建数据表
语法:
CREATE TABLE 表名 (
列名1 类型1 [约束],列名2 类型2 [约束],…);
常用类型:
INT(整型)
TEXT(文本字符串)
REAL(浮点数)
约束:
PRIMARY KEY //主键约束,可以确保该列数据唯一,还可以加快数据访问。
NOT NULL //非空约束,表示该类数据不能为空
eg:
sqlite> CREATE TABLE student (
…> id INT PRIMARY KEY,
…> name TEXT NOT NULL,
…> score REAL NOT NULL );
sqlite> .table
company student
2)删除数据表
语法:
DROP TABLE 表名;
注:慎用,因为数据表一旦删除,里面的数据也将随之消失
3)向数据表插入数据(增)
语法:
INSERT INTO 表名
(列名1,列名2…列名n)
VALUES(数值1,数值2…数值n);
eg:
sqlite> INSERT INTO company
…> (id,name,age,address,salary)
…> VALUES(10018,‘貂蝉’,28,‘山东’,8800.5);
sqlite> INSERT INTO company
…> (id,name,age,salary)
…> VALUES(10021,‘大乔’,31,13000);
sqlite> INSERT INTO company
…> VALUES(10022,‘孙权’,35,‘江西’,16000);
4)从数据表删除数据(删)
语法:
DELETE FROM 表名 WHERE 条件表达式;
条件1 and 条件2//同时满足两个条件
条件1 or 条件2//只需要满足其中一个条件
eg:
sqlite> DELETE FROM company
…> WHERE id=10029;
5)修改数据表中数据(修)
语法:
UPDATE 表名
SET 列名1=新数值,列名2=新数值,…
WHERE 条件表达式;
eg:
sqlite> UPDATE company SET age=45
…> WHERE id=10011;
sqlite> UPDATE company
…> SET salary=salary+2000
…> WHERE age>=30 and age<=35;
6)查询数据表中数据(查)
语法:
SELECT 列名1,列名2… FROM 表名
WHERE 条件表达式 LIKE ‘匹配模式’
ORDER BY 列名 排序方式;
注:匹配模式
% :匹配任意多个字符
_ : 匹配一个任意字符
注:排序方式
ASC:升序排序
DESC:降序排序
eg:
sqlite> SELECT * FROM company;
sqlite> SELECT * FROM company
…> WHERE salary>10000 or salary<3500;
sqlite> SELECT * FROM company
…> WHERE age LIKE ‘2_’;//匹配年龄2?
sqlite> SELECT * FROM company
…> WHERE name LIKE ‘孙%’;//匹配孙某某
sqlite> SELECT * FROM company
…> ORDER BY id ASC;//根据ID升序排序
sqlite> SELECT * FROM company
…> ORDER BY salary DESC;//根据工资降序排序
练习:创建一个表示学生成绩的数据表student,列的名字依次是id(学号)、name(姓名)、score(成绩)
1)向数据表插入如下数据
id name score
10001 杨健 80.5
10002 王建立 88.5
10005 孟建 90
10003 闵卫 99.5
10004 游成伟 59.5
10006 Jerry 100
…
2)删除Jerry
3)修改:游成伟成绩为66
4)查询:升序/降序
二 在Qt中使用Sqlite数据库
QT += sql
1 建立QT程序和数据库连接:QSqlDatabase
//添加数据库驱动
QSqlDatabase db =
QSqlDatabase::addDatabase(“QSQLITE”);
//设置数据库文件名字
db.setDatabaseName(“test.db”);
//打开数据库
bool ok = db.open();
2 执行SQL语句:QSqlQuery
QSqlQuery query;
QString str=QString(“Sql语句字符串”);
query.exec(str);
3 获取查询结果集:QSqlQueryModel
QSqlQueryModel model;
model.setQuery(“SELECT语句”);
//显示查询结果
QTableView view;
view.setModel(&model);
案例:学生成绩管理系统
工程名:Student
类名:StudentDialog
界面设计:
组合框(comboBox)
valueComboBox、condComboBox
按钮(PushButton):
sortButton(排序)、insertButton(插入)
deleteButton(删除)、updateButton(修改)
行编辑(LineEdit)
idEdit、nameEdit、scoreEdit
回顾:
1 常用SQL语句
1)创建数据表
CREATE TABLE 表名 (列名 类型 [约束],…);
2)删除数据表
DROP TABLE 表名;
3)插入数据
INSERT INTO 表名 (列名,…) VALUES(数值,…);
4)删除数据
DELETE FROM 表名 WHERE 条件表达式;
5)修改数据
UPDATE 表名 SET 列名=新数值 WHERE 条件表达式;
6)查询数据
SELECT 列名,… FROM 表名
WHERE 条件表达式 LIKE ‘匹配模式’
ORDER BY 列名 ASC/DESC;
2 Qt中使用数据库
1)添加数据驱动
QSqlDatabase db=QSqlDatabase::addDatabase(“QSQLITE”)
2)设置数据名字
db.setDatabaseName(“xx.db”);
3)打开时数据
db.open();
4)数据库操作
–》QSqlQuery
QSqlQuery query;
QString str=QString(“sql语句字符串”);
query->exec(str);
–》QSqlQueryModel
QSqlQueryModel model;
model.setQuery(“SELECT语句”);
今天:
一 QT多线程(QThread)
1 创建线程
1)方法一:QObject::moveToThread
class Worker : public QObject
{
Q_OBJECT
public slots:
//将来想在子线程中执行的函数
void doWork(…) {
/耗时或阻塞的操作/
}
};
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;//创建子线程对象
public:
Controller() {
//创建需要放在子线程中工作的Work对象
Worker *worker = new Worker;
//将worker对象移动到子线程中
worker->moveToThread(&workerThread);
//通过信号触发worker的槽(dowork)在子线程执行
connect(this, &Controller::operate,
worker, &Worker::doWork);
//开启子线程
workerThread.start();
}
signals:
void operate(const QString &);
};
2)方法二:继承QThread,重写run函数
class WorkerThread:public QThread{
Q_OBJECT
void run()[virtual]{
/* 耗时或阻塞操作 */
}
};
WorkerThread workerThread
workerThread.start();//开启子线程
2 相关的成员函数
1)开启线程//类似pthread_create()
void start();
2)获取线程句柄(ID)//类似pthread_self()
Qt::HANDLE currentThreadId()
3)线程退出//类似pthread_exit
void exit();
void quit()[slots];
4)线程等待//类似pthread_join()
void wait();
5)线程终止//类似pthread_cancel
void terminate();
void run(){
动态资源分配:new
...被终止...
动态资源释放: delete
}
-------------------
void run(){
加锁:lock
访问临界资源
...被终止...
访问临界资源结束
解锁:unlock
}
6)设置线程是否允许被终止
//类似pthread_setcancelstate
void setTerminationEnabled(bool enabled = true)
eg:
void run(){
setTerminationEnabled(false);//不允许被终止
关键代码:动态资源,临时资源,数据库…
setTerminationEnabled(true);//恢复可以终止
}
案例:多线程打印消息
方法1:工程Thread1
方法2: 工程Thread2
二 线程同步
1 互斥锁(互斥量) QMutex
QMutex mutex;
void run(void){
mutex.lock();
访问临界资源…;
mutex.unlock();
}
void run(void){
mutex.lock();
访问临界资源…;
mutex.unlock();
}
--------------------
void run(void){
mutex.lock();
…
if(“error1”){
mutex.unlock();
return;
}
…
if(“error2”){
mutex.unlock();
return;
}
mutex.unlock();
}
---------------
QMutex mutex;
void run(void){
//mutex.lock();
QMutexLocker locker(&mutex)
…
if(“error1”){
return;
}
…
if(“error2”){
return;
}
}
2 读写锁 QReadWriteLock
eg:
void ReaderThread::run(){//读操作线程
…
lock.lockForRead();
read_file();
lock.unlock();
…
}
void WriterThread::run(){//写操作线程
…
lock.lockForWrite();
write_file();
lock.unlock();
…
}
3 信号量 QSemaphore
eg:
//创建信号量并初始化为5,表示有5个共享资源
QSemaphore sem(5);//sem.available() == 5
//获取3个共享资源,剩余2个可用共享资源
sem.acquire(3);//sem.available() == 2
//获取2个共享资源,剩余0个可用共享资源
sem.acquire(2);//sem.available() == 0
//释放5个共享资源,剩余5个可用共享资源
sem.release(5);// sem.available() == 5
//又分配5个共享资源,剩余10个可用共享资源
sem.release(5);// sem.available() == 10
//尝试获取1,成功,返回true
sem.tryAcquire(1);//sem.available()==9//true
//尝试获取250,失败,返回false
sem.tryAcquire(250);//sem.available()==9//false
4 条件变量 QWaitCondition//了解
三 网络编程基础
1 Linux TCP/IP 四层/五层,OSI七层模型
1)应用层 HTTP/FTP/TFTP/POP3/SMTP/TFTP…
2)表示层
3)会话层
4)传输层 TCP/UDP
5)网络层 IP
6)链路层
7)物理层
2 IP地址
1)概念:互联网中唯一的地址
2)IPv4(32位) IPv6(128位)
3)IP地址表示方式
–》点分十进制“192.168.15.100”
–》struct sockaddr_in{0xC0A80F64};
–》QHostAddress
4)查看主机IP的指令
–》linux/unix:ifconfig
–》window:ipconfig
5)判断两台主机是否能否通信
ping 对方主机地址;
6)特殊的IP地址
–》127.0.0.1//本地环回地址,常用于本地测试
–》255.255.255.255//广播地址
–》0.0.0.0 //任意网卡的地址
2 TCP编程模型C/S
1)服务器
–》创建通信套接字 socket()
–》准备服务地址 struct sockaddr{ip,port};
–》绑定 bind()
–》监听 listen()
–》等待客户端连接请求 int cfd=accept()
–》创建子进程/子线程
–》在子进程/子线程通信
while(1){
read()/write()
recv()/send()
}
–》关闭 close()
2)客户端
–》创建和服务器通信的套接字 socket
–》准备服务器的地址 struct sockaddr{ip,port}
–》向服务器发送连接请求 connect()
–》通信
while(1){
read()/write()
recv()/send()
}
–》关闭 close()
2 UDP编程模型C/S
1)服务器
–》创建通信套接字 socket()
–》准备服务地址 struct sockaddr{ip,port};
–》绑定 bind()
–》通信
recvfrom()/sendto()
–》关闭 close()
2)客户端
–》创建通信套接字 socket()
–》准备服务地址 struct sockaddr{ip,port};
–》通信
read()/recvfrom()/sendto()
–》关闭 close()
QT中和网络编程相关类:
QHostAddress //IP地址
QAbstractSocket //套接字基类
QUdpSocket //UDP套接字
QTcpSocket //TCP套接字
QTcpServer //TCP服务器
回顾:
1 Qt多线程
1)创建线程方法1:moveToThread
class Myclass:public QObject{
Q_OBJECT
public slots:
void slot_func(…){
//将来要在子线程中执行代码
}
};
QThread thread;//子线对象
Myclass myObject;
myObject.moveToThread(&thread);
connect(xx,SIGNAL(xx),
&myObject,SLOT(slot_func()));
thread.start();
2)创建线程方法2:继承QThread,重写run函数
class MyClass:public QThread{
void run(void){
//将来要在子线程中执行代码
}
};
MyClass myObject;
myObject.start();
2 线程同步
1)互斥锁 QMutex
2)读写锁 QReadWriteLock
3)信号量 QSemaphore
4)条件变量 QWaitCondition
今天:
一 Qt的网络编程
1 QHostAddress//IP地址
1)构造IP地址对象
QHostAddress ip(“xx.xx.xx.xx”);
QHostAddress ip;
ip.setAddress(“xx.xx.xx.xx”);
2)特殊的IP地址
QHostAddress::LocalHost//127.0.0.1
QHostAddress::Broadcast//255.255.255.255
QHostAddress::Any //0.0.0.0
2 QAbstractSocket//套接字基类
1)绑定IP和端口
bool bind(IP,Port);
2)和服务器建立连接请求
void connectToHost(serverIP,serverPort);
3)断开连接
void disconnectFromHost();
4)获取套接字等待读取消息的字节数
qint64 bytesAvailable();
5)获取套接字状态
SocketState state();
注:表示断开连接QAbstractSocket::UnconnectedState
6)读/写 操作
read()/readAll()
write()
7)套接字有数据到来将发送信号
void readyRead(void)[signal]
8)网络通信异常时发送信号
error(QAbstractSocket::SocketError)[SIGNAL];
9)和服务器连接成功时发送信号
void connected()[signal]
10)和服务器断开连接时发送信号
void disconnected()[signal]
…
3 QUdpSocket//UDP套接字
1)判断是否有等待接收的数据包
bool hasPendingDatagrams();
2)获取等待数据包的大小
qint64 pendingDatagramSize();
3)读/写操作
readDatagram()/writeDatagram()
案例:UDP网络广播
1)发送端//类似客户端程序
–》指定广播地址:255.255.255.255
–》指定广播端口:8888
–》通过定时器,每隔1秒发送一次广播信息
2)接收端//类似服务器程序
–》绑定接收消息端口:8888
–》随时接收广播消息并显示
mkdir Broadcast
发送端工程:Sender
接收端工程:Receiver
4 QTcpSocket(TCP套接字)/QTcpServer(Tcp服务器)
eg:创建tcp服务器
QTcpServer server;
server.listen(IP,Port);
//当客户端和服务器建立连接时,发送信号newConnection
connect(&server,SIGNAL(newConnection()),
this,SLOT(slot_func()));
//获取和客户端通信的套接字
QTcpSocket* socket=server.nextPendingConnection();
案例:网络聊天室
1)服务器
–》使用QTcpServer创建Tcp服务器
–》响应客户端连接请求,保存和客户端通信套接字
–》接收客户端的聊天消息
–》转换聊天消息给其它客户端
2)客户端
–》使用QTcpSocket创建和服务器通信的套接字
–》和服务器建立连接
–》获取用户输入聊天消息,发送到服务器
–》接收服务器转发的聊天消息并显示
mkdir NetChat
1)服务器工程:Server
2)客户端工程:Client