QT

QT概述

Qt是一个跨平台的C++图形用户界面应用程序框架。

QT下载用清华的镜像,速度快。

QT优点

  • 跨平台
  • 接口简单
  • 简化了内存回收机制
  • 开发效率高
  • 有很好的社区氛围
  • 可以进行嵌入式开发

创建项目

Qwidget为父类 QMainWindow QDialog为子类 QMainWindow比父类多菜单栏、状态栏 QDialog对话框

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "mywidget.h"
#include <QApplication>//包含一个应用程序类的头文件
//命令行变量的数量 命令行变量的数组
int main(int argc, char *argv[])
{
//a为应用程序对象,在QT中有且仅有一个
QApplication a(argc, argv);
//窗口对象
myWidget w;
//调用show显示窗口
w.show();
//让应用程序对象进入消息循环,代码阻塞到当前行,不会一闪而过
return a.exec();
}

.por文件解释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
QT       += core gui //QT包含的模块

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets//大于4版本以上包含QT的widgets模块

TARGET = 01_project//目标 生成的.exe程序的名称
TEMPLATE = app //模板 应用程序模板 Application


DEFINES += QT_DEPRECATED_WARNINGS



SOURCES += \ //源文件
main.cpp \
mywidget.cpp

HEADERS += \ //头文件
mywidget.h

.h头文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#ifndef MYWIDGET_H
#define MYWIDGET_H
//命名规范
//类名 首字母大写 单词和单词之间首字母大写
//函数名 变量名称 首字母小写,单词和单词之间首字母大写
//快捷键
//注释 ctrl+/
//运行 ctrl+r
//编译 ctrl+b
//字体缩放 ctrl+滚轮
//查找 ctrl+f
//整行 ctrl+shift+↑或者↓
//帮助文档F1
//自动对齐 ctrl+i
//同名之间的.h与.cpp 快速切换 F4
#include <QWidget> //包含头文件 窗口类

class myWidget : public QWidget //继承
{
Q_OBJECT //宏,允许类中使用信号和槽的机制

public:
myWidget(QWidget *parent = 0); //构造函数
~myWidget();//析构函数
};

#endif // MYWIDGET_H

.cpp文件

1
2
3
4
5
6
7
8
9
10
11
12
#include "mywidget.h"

myWidget::myWidget(QWidget *parent)
: QWidget(parent)//初始化列表 如果不指定构造函数,则派生类会调用基类的默认构造函数,派生类构造函数的初始化列表只能初始化派生类成员,不能直接初始化继承成员,如果想 要调用基类的有参构造函数,则可以在派生类的初始化列表中显示指定
{
//一般自己写的代码
}

myWidget::~myWidget()
{

}

帮助文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
QPushButton Class
The QPushButton widget provides a command button. More...
//需要包含的头文件
Header:
#include <QPushButton>
//需要添加的模块
qmake:
QT += widgets
//父类
Inherits:
QAbstractButton
//子类
Inherited By:
QCommandLinkButton

List of all members, including inherited members

QPushButton 按钮的基本使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//创建一个按钮
QPushButton *btn=new QPushButton;
//btn.show();//show以顶层的方式弹出窗口
//让btn对象出现在mywidget窗口中
btn->setParent(this);
//设置文本
btn->setText("第一个按钮");
//设置控件大小
btn->resize(50,50);
//创建第二个按钮,按照控件大小创建窗口
QPushButton *btn1=new QPushButton("第二个按钮",this);
//两个按钮会在一块所以要移动
btn1->move(100,0);
//重置窗口大小
resize(600,400);
//设置固定窗口大小不可以移动
setFixedSize(600,400);
//设置窗口标题
setWindowTitle("第一个窗口");

对象树

概念

当常见的对象再堆区时,如果指定的父亲是QObject派生下来的类或者QObject的子类派剩下来的类,可以不用管理释放的操作,将对象放入对象树中

例子:new Teacher(this)

窗口不能再放入窗口的对象树中

作用

一定程度上简化了回收机制

综上所述 在QT中创建对象时就指定父类对象

坐标系

左上角为(0,0)X向右 y向下

信号和槽

connect(信号发送者,发送的信号(函数地址 siginal),信号接收者,信号处理(槽 slot 函数的地址,信号的地址)) 第五个参数多线程时才有意义,默认使用队列 如果是单线程默认直接 队列槽函数所在的线程和接收者一样 直接 槽函数所在的线程和发送者一样

例子:

1
connect(myBtn,&QPushButton::clicked,this,&myWidget::close);

信号槽的优点,松散耦合,信号发送端和接受段本身是没有关联的,通过connect连接将两端连接起来

自定义信号:

1
2
3
4
5
signals:
//自定义信号写在此处
//没有返回值 void 在信号里面只需要声明,不需要实现
//可以有参数,可以重载
void hungry();

自定义槽:

1
2
3
4
5
public slots:
//早期QT版本 必须要写到public slots,高级版本可以写到public下或者全局下
//返回值void 需要声明也需要实现
//可以有参数,可以发生重载
void treat();

自定义的连接

1
2
3
4
5
6
//创建一个老师的对象,学生的对象
this->zt=new Teacher(this);
this->st=new Student(this);
//先连接 connect(zt,&Teacher::hungry,st,&Student::treat);
//再触发
classIsOver();

自定义触发

1
2
3
void Widget::classIsOver(){
emit zt->hungry();
}

自定义的信号发送者,接收者 以及触发函数均需写在窗口类Widget的private中:

1
2
3
4
5
private:
Ui::Widget *ui;
Teacher *zt;
Student *st;
void classIsOver();

重载时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//重载
void hungry(QString foodName);
void Student::treat(QString foodName){
qDebug()<<"请老师吃"+foodName;
}
//connect(zt,&Teacher::hungry,st,&Student::treat);
//有多个信号和槽重载时用函数指针 函数类型(类名::参数名)(参数列表)=信号/槽
void(Teacher::*teacherSignal)(QString)=&Teacher::hungry;
void(Student::*studentSlot)(QString)=&Student::treat;
connect(zt,teacherSignal,st,studentSlot);
classIsOver();
//触发
void Widget::classIsOver(){
emit zt->hungry("宫保鸡丁");
}

信号连接信号

1
2
3
4
void(Teacher::*teacherSignal)(void)=&Teacher::hungry;
void(Student::*studentSlot)(void)=&Student::treat;
connect(zt,teacherSignal,st,studentSlot);
connect(btn,&QPushButton::clicked,zt,teacherSignal);

断开信号

1
2
3
4
5
6
7
8
9
10
disconnect(zt,teacherSignal,st,studentSlot);
参数为 信号发送者,发送的信号(函数地址 siginal),信号接收者,信号处理(槽 slot 函数的地址,信号的地址)
//信号是可以连接信号
//一个信号可以连接多个槽函数
//多个信号可以连接同一个槽函数
//信号和槽函数的参数一一对应
//信号的参数个数可以多余槽函数的个数,其余的类型也要一一对应 若出现信号参数少于槽函数参数个数 可以在槽函数用lambda
connect(btn,&QPushButton::clicked,this,[=](){
emit zt->hungry("宫爆鸡丁");
});

lambda表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*[标志着一个lambda的开始](参数)mutable->返回值类型{函数体};
[]
空表示没有任何函数对象参数
=表示lambda所在作用范围内所有可见的局部变量,为值传递方式
&表示lambda所在作用范围内所有可见的局部变量,为引用传递方式 不建议
this 类似于=
a 只允许看到a
&a 引用方式只允许看到a
a,&b a按照值传递,b按照引用传递
=,&a,&b 除a和b按引用进行传递外,其他都按照值传递
&,a,b 除a,b按照值传递其他都按照引用传递
()
mutable 可以省略 按值传递对象参数时,加上mutable修饰符后可以修改按值传递进来的拷贝(只能修改拷贝,不能修改值本身)
->返回值类型 有返回值时使用
*/

MainWindow

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
QMenuBar *bar=menuBar();//菜单栏最多只有一个
//将菜单栏放入到窗口中
setMenuBar(bar);
//创建菜单
QMenu * fileMenu=bar->addMenu("文件");
QMenu * editMenu=bar->addMenu("编辑");

//在文件下创建一个菜单项
QAction * newAction=fileMenu->addAction("新建");
//在新建和打开之间添加分隔符
fileMenu->addSeparator();
QAction * openAction=fileMenu->addAction("打开");


//工具栏 可以有多个
QToolBar * toolBar=new QToolBar(this);
addToolBar(Qt::LeftToolBarArea,toolBar);
//后期设置只允许工具栏左右停靠
toolBar->setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea);
//设置浮动
toolBar->setFloatable(false);
//设置移动 false之后工具栏不允许移动
toolBar->setMovable(false);
//在工具栏中添加内容
toolBar->addAction(newAction);
//工具栏添加分割线
toolBar->addSeparator();
toolBar->addAction(openAction);
//在工具栏中添加控件
QPushButton *btn=new QPushButton("aa",this);
toolBar->addWidget(btn);//状态栏 最多只有一个
QStatusBar * stBar=statusBar();
setStatusBar(stBar);
//标签控件
QLabel * lable=new QLabel("提示信息",this);
stBar->addWidget(lable);
//右侧
QLabel * lable2=new QLabel("提示信息",this);
stBar->addPermanentWidget(lable2);


//铆接窗口 (浮动窗口) 可以有多个
QDockWidget * dockWidget=new QDockWidget("浮动",this);
addDockWidget(Qt::BottomDockWidgetArea,dockWidget);
//设置后期停靠区域,只允许上下
dockWidget->setAllowedAreas(Qt::TopDockWidgetArea|Qt::BottomDockWidgetArea);

//设置中心部件 只能有一个
QTextEdit * edit=new QTextEdit(this);
setCentralWidget(edit);

使用ui设计时十分方便,若要在代码中获得某个部件 可使用 ui->部件名字

添加资源文件

1
//1.将要使用的文件添加到当前项目中2.在项目中添加新文件QtResource File 给资源文件起名字 res 生成res.qrc 打开方式右键open in editor 3.下方添加前缀 添加文件 4.使用“:+资源名+文件名”

对话框

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
connect(ui->actionnew,&QAction::triggered,this,[=](){
//对话框 分类
//模态对话框(不可以对其他窗口进行操作) 非模态对话框(可以对其他窗口进行操作)
//模态创建 阻塞 的功能 即对话框不点关闭就不会执行后续代码
QDialog *dlg=new QDialog(this);
dlg->resize(200,100);
dlg->exec();
qDebug()<<"模态框弹出来";

//非模态对话框
// QDialog *dlg2= new QDialog(this);//防止不会一闪而过
// dlg2->show();
// dlg2->setAttribute(Qt::WA_DeleteOnClose);//防止内存爆,关闭时释放掉
// dlg2->resize(200,100);
// qDebug()<<"非模态框弹出来";
});

标准对话框 QMessageBox

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//消息对话框  模态
//错误对话框
//QMessageBox::critical(this,"critical","错误");
//信息对话框
//QMessageBox::information(this,"1","2");
//提问对话框
//参数1 父亲 参数2 标题 参数3 提示内容 参数4 按键类型 参数5 默认关联回车的按键
//QMessageBox::question(this,"1","2",QMessageBox::Save|QMessageBox::Cancel,QMessageBox::Cancel);
//进行按键点击判断
// if(QMessageBox::Save==QMessageBox::question(this,"1","2",QMessageBox::Save|QMessageBox::Cancel,QMessageBox::Cancel)){
// qDebug()<<"保存";
// }else{
// qDebug()<<"取消";
// }
//警告对话框
QMessageBox::warning(this,"warning","警告");
});

其他对话框

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//其他对话框
//颜色对话框
// QColor color= QColorDialog::getColor(QColor(155,0,0));
// qDebug()<<color.blue();

//文件对话框 返回路径
//参数1 父亲 参数2 标题 参数3 路径 参数4 过滤的文件格式
// QString s=QFileDialog::getOpenFileName(this,"打开文件","E:/");
// qDebug()<<s;

//字体对话框
bool flag;
QFont q=QFontDialog::getFont(&flag,QFont("华文彩云",36));
qDebug()<<q;

页面布局

利用布局方式,给窗口进行美化

选取widget 进行布局 水平 垂直 栅格

默认窗口和控件之间有9间隙 ,选中窗口在 layout margin中调整

内部的间隙可以用弹簧分割 horizontal space

窗口默认特别大在sizePolicy中垂直策略改为fixed

文本款格式在echoMode中设置 需要密码框则选择为password

控件

按钮组

  • QPushButton 常用按钮
  • QToolButton 工具按钮用于显示 图片,如果想显示文字,修改风格 toolButtonStyle 凸起的风格 autoRaise
  • radiaButton 单选按钮,设置默认 setchecked
  • checkbox 多选按钮,2是选中 1是半选中 0是未选 状态代码
    1
    2
    3
    connect(ui->checkBox,&QCheckBox::stateChanged,this,[=](int state){
    qDebug()<<state;
    });

列表容器

QListWidget列表容器

1
2
3
4
5
6
7
8
//利用listWidget 写诗
// QListWidgetItem *item=new QListWidgetItem("锄禾日当午"); //一行
// ui->listWidget->addItem(item);
// item->setTextAlignment(Qt::AlignCenter); //位置
//全部直接添加
QStringList list;
list<<"锄禾日当午"<<"汗滴禾下锄";
ui->listWidget->addItems(list);

树控件

QTreeWidget 树控件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//设置水平头
ui->treeWidget->setHeaderLabels(QStringList()<<"英雄"<<"英雄介绍");
//每一行
QTreeWidgetItem * item=new QTreeWidgetItem(QStringList()<<"力量");
QTreeWidgetItem * item1=new QTreeWidgetItem(QStringList()<<"敏捷");
QTreeWidgetItem * item2=new QTreeWidgetItem(QStringList()<<"智力");
//加载顶层节点
ui->treeWidget->addTopLevelItem(item);
ui->treeWidget->addTopLevelItem(item1);
ui->treeWidget->addTopLevelItem(item2);
//追加子节点
QTreeWidgetItem * heroL1=new QTreeWidgetItem(QStringList()<<"刚被猪"<<"前排坦克,能在吸收伤害的同时造成客观的范围输出");
QTreeWidgetItem * heroL2=new QTreeWidgetItem(QStringList()<<"刚被猪"<<"前排坦克,能在吸收伤害的同时造成客观的范围输出");
item->addChild(heroL1);
item1->addChild(heroL2);
item2->addChild(heroL1);

QTableWidget表格控件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//tableWidget 控件
//设置列
ui->tableWidget->setColumnCount(3);
//设置表头
ui->tableWidget->setHorizontalHeaderLabels(QStringList()<<"姓名"<<"性别"<<"年龄");
//设置行数
ui->tableWidget->setRowCount(5);
QStringList nameList=QStringList()<<"亚瑟"<<"1"<<"2"<<"3"<<"4";
QStringList sex=QStringList()<<"亚瑟"<<"1"<<"2"<<"3"<<"4";
//设置正文
for(int i=0;i<5;i++){
int col=0;
ui->tableWidget->setItem(i,col++,new QTableWidgetItem(nameList[i]));
ui->tableWidget->setItem(i,col++,new QTableWidgetItem(sex.at(i)));
ui->tableWidget->setItem(i,col++,new QTableWidgetItem(QString::number(i)));
}

其他控件

栈控件 stackedWidget

下拉框 comboBox

QLable 显示图片、动图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//栈控件的使用
//ScrollArea 按钮
connect(ui->btn_scrollArea,&QPushButton::clicked,this,[=](){
ui->stackedWidget->setCurrentIndex(0);
});
//toolBox按钮
connect(ui->btn_ToolBox,&QPushButton::clicked,this,[=](){
ui->stackedWidget->setCurrentIndex(1);
});
//tabWidget按钮
connect(ui->btn_TabWidget,&QPushButton::clicked,this,[=](){
ui->stackedWidget->setCurrentIndex(2);
});

//下拉框
ui->comboBox->addItem("奔驰");
ui->comboBox->addItem("宝马");
ui->comboBox->addItem("兰博基尼");

connect(ui->pushButton_6,&QPushButton::clicked,this,[=](){
//ui->comboBox->setCurrentIndex(2);
ui->comboBox->setCurrentText("兰博基尼");
});

//利用QLable显示资源 可以显示动图
ui->label->setPixmap(QPixmap(":/image/la.jpg"));
//可以显示动图
//QMovie *movie=new QMovie();
//ui->label->setMovie(movie);
//movie->start();

自定义控件

  • 添加新文件 ->Qt->设计师界面类(.h .cpp .ui)
  • ui中设计QspinBox和QSlider 两个控件
  • Widget 使用自定义控件 首先拖拽 Widget 控件 其次提升为 写入类名 全局包含 添加
  • 信号和槽的监听 提供对外接口
  • 在主控制中使用

占位符

1
2
QString str=QString("鼠标点击了 x=%1  y=%2 ").arg(ev->x()).arg(ev->y());
%数字代表第几个arg的参数

事件 均需要在函数中进行重写

在ui中拖入后,提升为自己所写的类然后进行事件编辑

鼠标事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
name::name(QWidget *parent) : QLabel(parent)
{
//设置鼠标追踪 只要鼠标一移动就触发不用鼠标点击着移动
setMouseTracking(true);
}
void name::enterEvent(QEvent *event){
qDebug()<<"鼠标进入了";
}
void name::leaveEvent(QEvent *event){
qDebug()<<"鼠标离开了";
}
void name::mouseMoveEvent(QMouseEvent *ev){
//鼠标点击着移动
//移动的判断和点击不一样
// if(ev->buttons()&Qt::LeftButton){
// qDebug()<<"鼠标移动了";
// }
qDebug()<<"鼠标移动了";
}
void name::mousePressEvent(QMouseEvent *ev){
if(ev->button()==Qt::LeftButton){
QString str=QString("鼠标点击了 x=%1 y=%2 ").arg(ev->x()).arg(ev->y());
qDebug()<<str;}
}
void name::mouseReleaseEvent(QMouseEvent *ev){
qDebug()<<"鼠标松开了";
}

定时器1

利用时间timerevent

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//启动定时器 单位毫秒
id1=startTimer(1000);
id2=startTimer(2000);
}

MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::timerEvent(QTimerEvent *event){
if(event->timerId()==id1){
static int num=1;
ui->label_2->setText(QString::number(num++));
}else if(event->timerId()==id2){
static int num2=1;
ui->label_3->setText(QString::number(num2++));
}
}
1
2
3
4
5
6
7
8
9
10
11
//定时器第二种方式
QTimer * timer=new QTimer(this);
timer->start(500);
connect(timer,&QTimer::timeout,this,[=](){
static int num=1;
ui->label_4->setText(QString::number(num++));
});
//点击暂停
connect(ui->pushButton,&QPushButton::clicked,this,[=](){
timer->stop();
});

event事件

用于事件分发,也可以做拦截操作,不建议

1
2
3
4
5
6
7
8
9
10
11
12
13
bool name::event(QEvent *e){
//如果是鼠标按下,在event 事件分发来拦截
if(e->type()==QEvent::MouseButtonPress){
//类型转换
QMouseEvent * ev= static_cast<QMouseEvent *>(e);
QString str=QString("鼠标点击了 x=%1 y=%2 ").arg(ev->x()).arg(ev->y());
qDebug()<<str;
//true 表示用户自己处理这个事件,不向下分发
return true;
}
//其他事件交给父类处理
return QLabel::event(e);
}

事件过滤器

在事件分发前进行过滤

  • 给控件安装事件过滤器
  • 重写eventfilter事件
  • 
    

//安装事件过滤器
ui->label->installEventFilter(this);
//重写eventFilter事件
bool MainWindow::eventFilter(QObject *watched, QEvent *event){
if(watched==ui->label){
if(event->type()==QEvent::MouseButtonPress){
return true;
}
}
return QWidget::eventFilter(watched,event);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

#### 绘图事件

```js
void MainWindow::paintEvent(QPaintEvent *){
//实例化画家
QPainter *painter=new QPainter(this);//指明绘图设备
//设置画笔
QPen *pen=new QPen(QColor(0,255,0));
pen->setWidth(3);
pen->setStyle(Qt::DotLine);
painter->setPen(*pen);
//设置画刷
QBrush *brush=new QBrush(QColor(0,0,255));
brush->setStyle(Qt::Dense7Pattern);
painter->setBrush(*brush);
//线
painter->drawLine(QPoint(0,0),QPoint(100,100));
//圆
painter->drawEllipse(QPoint(100,100),50,50);
//矩形
painter->drawRect(QRect(QPoint(100,100),QPoint(200,200)));
//字
painter->drawText(QRect(10,200,100,50),"好好学习");


---------高级设置---------
QPainter painter(this);
// painter.drawEllipse(QPoint(100,50),50,50);
// //设置抗锯齿效率比较低
// painter.setRenderHint(QPainter::Antialiasing);
// painter.drawEllipse(QPoint(200,50),50,50);

painter.drawRect(QRect(20,20,50,50));
//让画家移动100
painter.translate(100,0);

//保存画家状态
painter.save();
painter.drawRect(QRect(20,20,50,50));
//还原画家的状态
painter.restore();
painter.drawRect(QRect(20,20,50,50));
}
//利用画家 画资源文件
QPainter painter(this);
painter.drawPixmap(x,20,100,100,QPixmap(":/image/la.jpg"));
//超过屏幕宽度就返回
if(x>this->width()){
x=0;
}

绘图设备

Qpixmap QImage QBitmap(黑白色) Qpicture QWidget

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
ui->setupUi(this);
// //绘图设备
// QPixmap pix(300,300);
// //设置设备的背景
// pix.fill(Qt::white);
// QPainter painter(&pix);
// painter.setPen(QPen(Qt::green));
// painter.drawEllipse(QPoint(50,50),50,50);
// //保存
// pix.save("E://1.jpg");

// //可以对每一个像素进行访问
// QImage image(300,300,QImage::Format_RGB666);
// image.fill(Qt::white);
// QPainter painter(&image);
// painter.drawEllipse(QPoint(50,50),50,50);
// image.save("E:/1.jpg");
//QPicture 绘图设备 可以记录和重新绘图指令
QPicture pic;
QPainter painter;
painter.begin(&pic);
painter.setBrush(QBrush(QColor(Qt::blue)));
painter.drawEllipse(QPoint(50,50),50,50);
painter.end();
pic.save("E:/pic.zt");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void MainWindow::paintEvent(QPaintEvent *event){
//利用Qimage对像素进行修改
QPainter painter(this);
// QImage img;
// img.load(":/image/la.jpg");
// for(int i=50;i<100;i++){
// for(int j=50;j<100;j++){
// img.setPixel(QPoint(i,j),qRgb(255,0,0));
// }
// }
// painter.drawImage(0,0,img);

//重现QPicture 的绘图指令
QPicture pic;
pic.load("E:/pic.zt");
painter.drawPicture(0,0,pic);
}

文件操作

文件读写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//编码格式
//QTextCodec *code=QTextCodec::codecForName("gbk");
//读文件 默认支持的格式为utf-8
QFile file(s);
//设置打开方式
file.open(QIODevice::ReadOnly);
//全读
QByteArray array=file.readAll();
//一行一行
QByteArray a;
//判断是否读到文件尾部
while(!file.atEnd()){
a+=file.readLine();
}
ui->textEdit->setText(array);
//ui->textEdit->setText(code->toUnicode(array));
//关闭文件
file.close();

//追加的方式写文件
file.open(QIODevice::Append);
file.write("111");
file.close();

文件信息读取

1
2
3
4
//文件的信息
QFileInfo info(s);
qDebug()<<info.suffix();
//想读取哪些信息看帮助文档

网络通信

tcp

在pro文件中加入network 模块

1
QT       += core gui network

服务器端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpServer> //监听套接字
#include <QTcpSocket> //通信套接字
namespace Ui {
class Widget;
}

class Widget : public QWidget
{
Q_OBJECT

public:
explicit Widget(QWidget *parent = 0);
~Widget();

private slots:
void on_btn_send_clicked();

void on_btn_close_clicked();

private:
Ui::Widget *ui;
QTcpServer *tcpServer;
QTcpSocket *tcpSocket;
};

#endif // WIDGET_H




#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
tcpServer=NULL;
tcpSocket=NULL;
//监听套接字
tcpServer=new QTcpServer(this);
//监听任意ip 端口为8888
tcpServer->listen(QHostAddress::Any,8888);
setWindowTitle("服务器8888");
//建立连接
connect(tcpServer,&QTcpServer::newConnection,this,[=](){
//取出建立好的套接字
tcpSocket=tcpServer->nextPendingConnection();
//获取对方的ip和端口
QString ip=tcpSocket->peerAddress().toString();
qint16 port=tcpSocket->peerPort();

QString temp=QString("[%1:%2]:成功连接").arg(ip).arg(port);
ui->text_read->setText(temp);


connect(tcpSocket,&QTcpSocket::readyRead,this,[=](){
//从通信套接字中取出内容
QByteArray array=tcpSocket->readAll();
ui->text_read->append(array);
});
});


}

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

void Widget::on_btn_send_clicked()
{
if(NULL==tcpSocket){
return;
}
//获取编辑区内容
QString str=ui->text_write->toPlainText();
//给对方发送数据 使用tcpSocket套接字
tcpSocket->write(str.toUtf8().data());
}

void Widget::on_btn_close_clicked()
{
if(NULL==tcpSocket){
return;
}
//主动和客户端断开连接
tcpSocket->disconnectFromHost();
tcpSocket->close();
tcpSocket=NULL;
}

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#ifndef CLIENTWIDGET_H
#define CLIENTWIDGET_H

#include <QWidget>
#include <QTcpSocket>
namespace Ui {
class ClientWidget;
}

class ClientWidget : public QWidget
{
Q_OBJECT

public:
explicit ClientWidget(QWidget *parent = 0);
~ClientWidget();

private slots:
void on_connect_clicked();

void on_send_clicked();

void on_close_clicked();

private:
Ui::ClientWidget *ui;
QTcpSocket *tcpSocket;//通信套接字
};

#endif // CLIENTWIDGET_H



#include "clientwidget.h"
#include "ui_clientwidget.h"
#include <QHostAddress>
ClientWidget::ClientWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::ClientWidget)
{
ui->setupUi(this);
setWindowTitle("客户端");
tcpSocket=NULL;
//分配空间指定父对象
tcpSocket=new QTcpSocket(this);
connect(tcpSocket,&QTcpSocket::connected,[=](){
ui->textEdit_read->setText("成功和服务器建立");
});
connect(tcpSocket,&QTcpSocket::readyRead,[=](){
QByteArray array=tcpSocket->readAll();
ui->textEdit_read->append(array);
});
}

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

void ClientWidget::on_connect_clicked()
{
if(NULL==tcpSocket){
return;
}
QString ip=ui->lineEdit_ip->text();
qint16 port=ui->lineEdit_port->text().toInt();
tcpSocket->connectToHost(QHostAddress(ip),port);

}

void ClientWidget::on_send_clicked()
{
if(NULL==tcpSocket){
return;
}
//获取编辑框内容
QString str=ui->textEdit_2->toPlainText();
tcpSocket->write(str.toUtf8().data());
}

void ClientWidget::on_close_clicked()
{
//主动和对方断开连接
tcpSocket->disconnectFromHost();
tcpSocket->close();
}

udp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(int i,QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
udpSocket=new QUdpSocket(this);
//绑定端口
udpSocket->bind(i);
setWindowTitle(QString("服务器端口为%1").arg(i));
//当对方成功发送数据过来 自动触发readyRead
connect(udpSocket,&QUdpSocket::readyRead,this,&Widget::dealMsg);
}

Widget::~Widget()
{
delete ui;
}
void Widget::dealMsg(){
QHostAddress cliAddr;//对方地址
quint16 port;//对方地址
//读取对方发送的数据
char buf[1024]={0};
qint64 len=udpSocket->readDatagram(buf,sizeof(buf),&cliAddr,&port);
if(len>0){
QString str=QString("[%1:%2]%3").arg(cliAddr.toString()).arg(port).arg(buf);
ui->textEdit->setText(str);
}
}

void Widget::on_btn_send_clicked()
{
//获取对方的ip和端口
QString ip=ui->lineEdit_ip->text();
qint16 port=ui->lineEdit_port->text().toInt();
//获取编辑区内容
QString str=ui->textEdit->toPlainText();
//给ip发送内容
udpSocket->writeDatagram(str.toUtf8(),QHostAddress(ip),port);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QUdpSocket>//UDP套接字
namespace Ui {
class Widget;
}

class Widget : public QWidget
{
Q_OBJECT

public:
explicit Widget(int i=8888,QWidget *parent = 0);
~Widget();
void dealMsg();//处理对方发过来的数据
private slots:
void on_btn_send_clicked();

private:
Ui::Widget *ui;
QUdpSocket *udpSocket;
};

#endif // WIDGET_H

组播

1
2
3
4
5
6
7
8
9
10
//绑定端口
//使用组播时不能这样写
//udpSocket->bind(i);
udpSocket->bind(QHostAddress::AnyIPv4,i);
//加入某个组播 QQ群 组播地址必须为D类
udpSocket->joinMulticastGroup(QHostAddress("224.0.0.2"));
//退出组播 udpSocket->leaveMulticastGroup(QHostAddress(""))
setWindowTitle(QString("服务器端口为%1").arg(i));
//当对方成功发送数据过来 自动触发readyRead
connect(udpSocket,&QUdpSocket::readyRead,this,&Widget::dealMsg);

发文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFileDialog>
#include <QDebug>
#include <QFileInfo>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//监听套接字
tcpServer=new QTcpServer(this);
//监听
tcpServer->listen(QHostAddress::Any,8888);
setWindowTitle("服务器端口为8888");
//两个按钮默认不能点击
ui->btn_select->setEnabled(false);
ui->btn_send->setEnabled(false);
//连接成功 触发newconnect
connect(tcpServer,&QTcpServer::newConnection,this,[=](){
//取出套接字
tcpSocket=tcpServer->nextPendingConnection();
//获取对方ip和端口
QString ip=tcpSocket->peerAddress().toString();
quint16 port=tcpSocket->peerPort();
QString str=QString("[%1:%2]成功连接").arg(ip).arg(port);
ui->textEdit->setText(str);
//按钮可以
ui->btn_select->setEnabled(true);
});

connect(&timer,&QTimer::timeout,this,[=](){
timer.stop();
sendData();
});
}

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

void MainWindow::on_btn_select_clicked()
{
QString path=QFileDialog::getOpenFileName(this,"open","../");
if(false== path.isEmpty()){
//获取文件信息
fileName.clear();
fileSize=0;
sendSize=0;
QFileInfo info(path);
fileName=info.fileName();
fileSize=info.size();
file.setFileName(path);
bool isOk=file.open(QIODevice::ReadOnly);
if(!isOk){
qDebug()<<"打开失败";
}
ui->textEdit->append(path);
ui->btn_select->setEnabled(false);
ui->btn_send->setEnabled(true);
}else{
qDebug()<<"选择文件路径出错";
}
}

void MainWindow::on_btn_send_clicked()
{
//先发送文件头
QString head=QString("%1##%2").arg(fileName).arg(fileSize);
qint64 len=tcpSocket->write(head.toUtf8());
if(len>0){//头部发送成功
//防止Tcp黏包问题 ,需要延时20ms
timer.start(20);
}else{
qDebug()<<"头部信息发送失败";
file.close();
ui->btn_select->setEnabled(true);
ui->btn_send->setEnabled(false);
}
}
void MainWindow::sendData(){
qint64 len=0;
do{
//每次发送4k
char buf[4*1024]={0};
len=0;
len=file.read(buf,sizeof(buf));
//发送数据 都多少发多少
len=tcpSocket->write(buf,len);
//发送数据要累加
sendSize+=len;
}while(len>0);
if(sendSize==fileSize){
ui->textEdit->append("文件发送完毕");
file.close();
tcpSocket->disconnectFromHost();
tcpSocket->close();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QTcpServer> //监听套接字
#include <QTcpSocket> //通信套接字
#include <QFile>
#include <QTimer>
namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
Q_OBJECT

public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();

private slots:
void on_btn_select_clicked();

void on_btn_send_clicked();
void sendData();
private:
Ui::MainWindow *ui;
QTcpServer *tcpServer;//监听套接字
QTcpSocket *tcpSocket;//通信套接字
QFile file;
QString fileName;
qint64 fileSize;
qint64 sendSize;
QTimer timer;
};

#endif // MAINWINDOW_H
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#ifndef CLIENTWIDGET_H
#define CLIENTWIDGET_H

#include <QWidget>
#include <QTcpSocket>
#include <QFile>
namespace Ui {
class ClientWidget;
}

class ClientWidget : public QWidget
{
Q_OBJECT

public:
explicit ClientWidget(QWidget *parent = 0);
~ClientWidget();

private slots:
void on_btn_connect_clicked();

private:
Ui::ClientWidget *ui;
QTcpSocket *tcpSocket;
QFile file;
QString fileName;
qint64 fileSize;
qint64 recvSize;
bool isStrat;
};

#endif // CLIENTWIDGET_H
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include "clientwidget.h"
#include "ui_clientwidget.h"
#include <QDebug>
#include <QMessageBox>
#include <QHostAddress>
ClientWidget::ClientWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::ClientWidget)
{
ui->setupUi(this);
isStrat=true;
tcpSocket=new QTcpSocket(this);
connect(tcpSocket,&QTcpSocket::readyRead,[=](){
//取出接收的内容
QByteArray array=tcpSocket->readAll();
if(isStrat==true){
//头信息
isStrat=false;
fileName=QString(array).section("##",0,0);
fileSize=QString(array).section("##",1,1).toInt();
recvSize=0;

file.setFileName(fileName);
bool isOk=file.open(QIODevice::WriteOnly);
if(isOk==false){
qDebug()<<"写失败";
}
}else{
//文件信息
qint64 len=file.write(array);
recvSize+=len;
if(recvSize==fileSize){
file.close();
QMessageBox::information(this,"完成","文件接收完成");
tcpSocket->disconnectFromHost();
tcpSocket->close();
}
}
});
}

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

void ClientWidget::on_btn_connect_clicked()
{
//获取服务器ip和端口
QString ip=ui->ip->text();
qint64 port=ui->port->text().toInt();
tcpSocket->connectToHost(QHostAddress(ip),port);
}

线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>

class Mythread : public QThread
{
Q_OBJECT
public:
explicit Mythread(QThread *parent = nullptr);
protected:
//QThread的虚函数
//线程处理函数
//不能直接调用需要通过start()间接调用
void run();
signals:
void isDone();
public slots:
};

#endif // MYTHREAD_H
1
2
3
4
5
6
7
8
9
10
11
#include "mythread.h"

Mythread::Mythread(QThread *parent) : QThread(parent)
{

}
void Mythread::run(){
//很复杂的下数据处理需要耗时
sleep(5);
emit isDone();
}
1
2
3
thread->quit();
//等待线程处理完毕
thread->wait();
1
thread->start();//开启线程

第二种方式见MyWidget项目

数据库

将libmysql.dll文件放到QT/bin下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
QSqlDatabase db=QSqlDatabase::addDatabase("QMYSQL");
db.setHostName("localhost");
db.setUserName("root");
db.setPassword("123456");
db.setDatabaseName("student");
//打开数据库
if(!db.open()){
qDebug()<<db.lastError().text();
return;
}
QSqlQuery query;
//创建数据库 插入 删除
//query.exec("INSERT INTO student (xueHao) VALUES ('181451081115');");
//预处理 占位符 批量插入 odbc风格
// query.prepare("INSERT INTO student (xueHao) VALUES (?);");
// QVariantList xueHao;
// xueHao<<"181451081113"<<"181451081139";
// query.addBindValue(xueHao);
// query.execBatch();
//预处理 占位符 批量插入 oracle风格
// query.prepare("INSERT INTO student (xueHao) VALUES (:xueHao);");
// QVariantList xueHao;
// xueHao<<"181451081110"<<"181451081130";
// query.bindValue(":xueHao",xueHao);
// query.execBatch();
//开启事务
// QSqlDatabase::database().transaction();
// QSqlQuery query1;
// query1.exec("delete from student where xuehao = '181451081110'");
// //执行事务
// QSqlDatabase::database().commit();
// //回滚事务
// QSqlDatabase::database().rollback();
query.exec("select * from student");
while(query.next()){//遍历
qDebug()<<query.value(0).toString()<<query.value("xueHao").toString();
}
//修改
qDebug()<<query.exec("update student set zhuanYeBanJi='11' where xueHao = '181451081111'");
//数据库操作执行成功返回true失败返回false

数据库控件直接操作数据库不需要命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//设置模型
QSqlTableModel *model = new QSqlTableModel(this);
model->setTable("student");//制定使用哪个表
//把model放到View
ui->tableView->setModel(model);
//显示数据
model->select();
//将表头第几个变为什么标题
// model->setHeaderData(0,Qt::Horizontal,"学号");
//设置手动提交修改
//model->setEditStrategy(QSqlTableModel::OnManualSubmit);
//执行手动提交
//model->submitAll();
//取消所有动作
//model->revertAll();
//设置不允许修改
//ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);

//增加数据
//添加空记录
// QSqlRecord record=model->record();
// //获取行号
// int row=model->rowCount();
// model->insertRecord(row,record);

//取出选中的模型
QItemSelectionModel *sModel=ui->tableView->selectionModel();
//取出选中的索引
QModelIndexList list=sModel->selectedRows();
for(int i=0;i<list.size();i++)
{
model->removeRow(list.at(i).row());
}


//查找
//取出where后面的关键字符串放入下面函数的参数中
model->setFilter();
model->select();