QT笔记


QT笔记

1、qt开发的快捷键

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//注释
ctrl + /
//运行
ctrl + r
//编译
ctrl + b
//字体缩放
ctrl +鼠标滚轮
//查找
ctrl + f
//整行移动
ctrl + shift +或者↓
//自动对齐
ctrl + i;
//同名之间的.h和.cpp切换
F4
//帮助文档第一种方式 F1 第二种左侧按钮 第三种 c: \gt\gt5.6.0\5.6\mingw49_32\bin

2、窗口显示 show

窗口widget显示可以调用 show() 但是这个是以顶层的方式进行弹出显示

qt的坐标系为

image-20240728162443462

3、创建按钮

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//1.首先要包含头文件
#include<QPushButton>

//2.创建按钮
QPushButton *btn = new QPushButton;
btn->setParent(this);
btn->setText("按钮");

//3.创建按钮的第二个方式(但是会出现以控件的大小来创建窗口)
QPushButton *btn2 = new QPushButton("按钮2",this);

//指定窗口大小
resize(600,400);

//移动btn2按钮
btn2->move(100,100);

//设置固定窗口大小
setFixedSize(600,400);

4.QDebug的使用

像命令行一样进行输出信息

首先需要包含头文件

#include<QDebug>

输出

qDebug() << "Hello World";

4、绑定事件

信号可以绑定事件 也可以绑定 信号

一个信号可以绑定多个槽函数

多个信号 可以绑定一个槽函数

connect(信号的发送者,发送的信号,信号的接受者,处理的槽函数)

connect(sender, SIGNAL(signalName()), receiver, SLOT(slotName()));

  • sender:发射信号的对象名称
  • signalName():信号名称
  • receiver:接收信号的对象名称,一般情况下为槽函数所属对象,写this即可
  • slotName():槽函数名称

①自定义的信号

只需要声明 不需要实现

写在 signals

②自定义的槽函数

可以写在全局函数 也可以写在对象的public下

③信号和槽函数的参数

信号的参数个数 大于等于 槽函数的参数个数

信号和槽函数的参数类型必须一致

1.信号和槽函数具有相同数量和类型的参数。这时可以直接连接且无需出现函数参数:

connect(lineEdit, &QLineEdit::textChanged, this, &Widget::do_textChanged);
在上面示例中,信号textChanged(QString)和槽函数do_textChanged(QString)参数相同。

2.信号的参数多于槽函数的参数。槽函数将忽略信号的多余参数,这个特性允许你在信号和槽参数不完全匹配的情况下,仍然能够正常工作。正常情况下,不推荐把槽函数设计为overload型。

3.某些信号的参数有默认值。也就是说同一信号的参数分为有参数和无参数,如QCheckBox的clicked()信号和clicked(bool)信号。这时connect()函数有两种写法:

a.设置不同名字的槽函数:

1
2
3
4
5
6
//槽函数
void do_checked(bool checked);
void do_checked_NoParam();
//connect()函数
connect(checkBox, &QCheckBox::clicked, this, &Widget::do_checked);
connect(checkBox, &QCheckBox::clicked, this, &Widget::do_checked_NoParam);

b.使用模板函数qOverload()来明确参数类型:

1
2
connect(checkBox, &QCheckBox::clicked, this, qOverload<bool>(&Widget::do_checked));
connect(checkBox, &QCheckBox::clicked, this, qOverload<>(&Widget::do_checked));

④样例—QT_001

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

connect(btn2,&QPushButton::clicked,this,&button_clicked);

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
#include "mywidget.h"
#include "ui_mywidget.h"


//构造函数
myWidget::myWidget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::myWidget)
{
ui->setupUi(this);

//创建老师对象
this->t = new Teacher(this);


//创建按钮
QPushButton *btn1 = new QPushButton;
btn1->setParent(this);
btn1->setText("按钮1");

//创建按钮的第二个方式(但是会出现以控件的大小来创建窗口)
QPushButton *btn2 = new QPushButton("按钮2",this);

//指定窗口大小
resize(600,400);

//移动btn2按钮
btn2->move(100,100);

//设置固定窗口大小
setFixedSize(600,400);

//按钮1绑定事件
connect(btn1, &QPushButton::clicked, this, &myWidget::close);

//按钮2绑定事件 自定义槽函数
//按钮2点击后 触发treat函数
// connect(btn2, &QPushButton::clicked, this, [this](){
// t->treat();
// });
//connect(btn2,&QPushButton::clicked,this,&button_clicked);
connect(btn2,&QPushButton::clicked,t,&Teacher::test);

//自定义无参数的信号和槽函数
void(Teacher::*Signal)() = &Teacher::hungry;
void(Teacher::*Slot)() = &Teacher::treat;
connect(t,Signal,t,Slot);
//在调用action后 会发出hungry的信号 从而调用treat函数
action();

//自定义带参数的信号和槽函数(存在两个版本 编译器无法找到是哪一个函数)
//后面的(QString)就代表了是有参数的
void(Teacher::*teacherSignal)(QString) = &Teacher::hungry;
void(Teacher::*teacherSlot)(QString) = &Teacher::treat;
connect(t,teacherSignal,t,teacherSlot);
action();
}

void myWidget::action()
{
//emit t->hungry();
emit t->hungry("鱼香肉丝");
}

void button_clicked()
{
qDebug() << "按钮被点击了";
}

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

5、QString转为char *类型

str.toUtf8().data()

6、Lambda表达式

C++中lambda表达式的构成

[函数对象参数] (操作符重载函数参数) mutable ->返回值{函数体}

1
2
3
4
[capture] (parameters) mutable ->return-type
{
statement
}

① 函数对象参数;

[],标识一个Lambda的开始,这部分必须存在,不能省略。函数对象参数是传递给编译器自动生成的函数对象类的构造函数的。函数对象参数只能使用那些到定义Lambda为止时Lambda所在作用范围内可见的局部变量(包括Lambda所在类的this)。函数对象参数有以下形式:

空。没有使用任何函数对象参数。

​ =。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是值传递方式(相当于编译器自动为我们按值传递了所有局部变量)。

​ &。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是引用传递方式(相当于编译器自动为我们按引用传递了所有局部变量)。

​ this。函数体内可以使用Lambda所在类中的成员变量。

​ a。将a按值进行传递。按值进行传递时,函数体内不能修改传递进来的a的拷贝,因为默认情况下函数是const的。要修改传递进来的a的拷贝,可以添加mutable修饰符。

​ &a。将a按引用进行传递。

​ a, &b。将a按值进行传递,b按引用进行传递。

​ =,&a, &b。除a和b按引用进行传递外,其他参数都按值进行传递。

​ &, a, b。除a和b按值进行传递外,其他参数都按引用进行传递。

② 操作符重载函数参数;

​ 标识重载的()操作符的参数,没有参数时,这部分可以省略。参数可以通过按值(如:(a,b))和按引用(如:(&a,&b))两种方式进行传递。

③ 可修改标示符;

​ mutable声明,这部分可以省略。按值传递函数对象参数时,加上mutable修饰符后,可以修改按值传递进来的拷贝(注意是能修改拷贝,而不是值本身)

1
2
3
4
5
6
7
8
9
10
11
QPushButton * myBtn = new QPushButton (this);

QPushButton * myBtn2 = new QPushButton (this);

myBtn2->move(100,100);

int m = 10;
connect(myBtn,&QPushButton::clicked,this,[m] ()mutable { m = 100 + 10; qDebug() << m; });
connect(myBtn2,&QPushButton::clicked,this,[=] () { qDebug() << m; });

qDebug() << m;

④ 函数返回值;

​ ->返回值类型,标识函数返回值的类型,当返回值为void,或者函数体中只有一处return的地方(此时编译器可以自动推断出返回值类型)时,这部分可以省略。

⑤ 是函数体;

​ {},标识函数的实现,这部分不能省略,但函数体可以为空。

7、菜单栏和工具栏

QMenuBar QToolBar

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
//创建菜单栏只能有一个(所以用setMenuBar)
QMenuBar *bar = menuBar();
//将菜单栏放在窗口中
setMenuBar(bar);
//创建菜单
QMenu *file = bar->addMenu("文件");
QMenu *edit = bar->addMenu("编辑");
//创建菜单项
QAction *new_action = file->addAction("新建");
//创建菜单的分隔符
file->addSeparator();
QAction *open_action =file->addAction("打开");


//创建工具栏 可以有多个(所以用addToolBar)
QToolBar *toolBar = new QToolBar(this);

//将工具栏放在窗口中
addToolBar(toolBar);

//工具栏的设置
//设置只能左右停靠
toolBar->setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea);
//设置浮动
toolBar->setFloatable(false);
//设置移动
toolBar->setMovable(false);

//设置工具栏内容
toolBar->addAction("工具一");
toolBar->addAction("工具二");

//工具栏添加控件
QPushButton *btn = new QPushButton("工具",this);
toolBar->addWidget(btn);

8、状态栏

QStatusBar

1
2
3
4
5
6
7
8
9
//状态栏
QStatusBar *statusBar = new QStatusBar();
//设置状态栏到窗口中
setStatusBar(statusBar);
//放标签控件
QLabel * label = new QLabel("左侧提示信息",this);
statusBar->addWidget(label);
QLabel * label2 = new QLabel("右侧提示信息",this);
statusBar->addPermanentWidget(label2);

9、铆接部件(浮动窗口)

QDockWidget

1
2
3
4
5
6
7
8
9
10
//铆接部件(浮动窗口) 可以有多个
QDockWidget *dockwidhet = new QDockWidget("浮动",this);
//设置在窗口的下方
addDockWidget(Qt::BottomDockWidgetArea ,dockwidhet);
//设置后期停靠区域 只允许上下
dockwidhet->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);

//设置 编辑器 为中心部件(仅有一个)
QTextEdit *edit_text = new QTextEdit(this);
setCentralWidget(edit_text);

10、添加资源项目

①将文件拷贝到当前项目位置处

②右键项目–添加新文件 选择QT–QT Resource File

image-20240731144637139

image-20240731144657856

③生成后缀为 qrc 的文件

image-20240731144743096

④添加前缀并且添加文件 即可添加成功资源文件

image-20240731144832303

⑤使用资源文件

1
2
3
//使用qt资源
ui->actionnew->setIcon(QIcon(":/1test.png"));
ui->actionopen->setIcon(QIcon(":/2test.png"));

image-20240731145219545

11、模态和非模态

模态对话框–不可以对其他窗口进行操作

非模态对话框–可以对其他窗口进行操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//绑定事件 点击新建 弹出对话框
connect(ui->actionnew, &QAction::triggered,[=](){
//对话框
//1.模态对话框--不可以对其他窗口进行操作
QDialog dlg(this);
dlg.resize(200,200);
dlg.exec();
qDebug() << "模态对话框弹出";
//2.非模态对话框--可以对其他窗口进行操作
QDialog *dlg2 = new QDialog(this);//创建在堆 当函数结束的时候 不会消失
dlg2->setAttribute(Qt::WA_DeleteOnClose);//设置当对象关闭的之后进行释放
dlg2->resize(200,200);
dlg2->show();
}

12、消息对话框

得到用户点击的按钮

1
2
3
4
5
6
7
8
9
//ret存储的是用户点击的按钮
int ret = QMessageBox::question(this,"question","问题");
if (ret == QMessageBox::Yes)
{
qDebug() << "用户点击了“确定”按钮";
} else if (ret == QMessageBox::No)
{
qDebug() << "用户点击了“取消”按钮";
}

参数1:父亲对象

参数2:标题

参数3:文本内容

参数4:按键类型

参数5 : 默认按钮

①错误消息对话框

QMessageBox::critical(this,"critical","错误");

image-20240731151328516

②信息对话框

QMessageBox::information(this,"info","信息");

image-20240731151501724

③提问对话框

QMessageBox::question(this,"question","问题");

image-20240731151554655

④警告对话框

QMessageBox::warning(this,"warning","警告");

image-20240731153454528

⑤颜色对话框

QColor color = QColorDialog::getColor(QColor(255,0,0)); qDebug() << color.red() << color.blue() << color.green();

image-20240731153922383

⑥文件对话框

文件对话框 参数1–父亲 参数2–标题 参数3–默认打开路径 参数4–过滤文件
QString path = QFileDialog::getOpenFileName(this,"打开文件","C:\\Users\\ZW\\Desktop","(*.txt)");

⑦字体对话框

bool flag; QFont select = QFontDialog::getFont(&flag,QFont("宋体",36));

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
//绑定事件 点击新建 弹出对话框
connect(ui->actionnew, &QAction::triggered,[=](){
//对话框
//1.模态对话框--不可以对其他窗口进行操作
// QDialog dlg(this);
// dlg.resize(200,200);
// dlg.exec();
// qDebug() << "模态对话框弹出";
//2.非模态对话框--可以对其他窗口进行操作
// dlg2 = new QDialog(this);//创建在堆 当函数结束的时候 不会消失
// dlg2->setAttribute(Qt::WA_DeleteOnClose);//设置当对象关闭的之后进行释放
// dlg2->resize(200,200);
// dlg2->show();

//消息对话框
//错误对话框
//QMessageBox::critical(this,"critical","错误");
//信息对话框
//QMessageBox::information(this,"info","信息");
//提问对话框
// int ret = QMessageBox::question(this,"question","问题");
// if (ret == QMessageBox::Yes)
// {
// qDebug() << "用户点击了“确定”按钮";
// } else if (ret == QMessageBox::No)
// {
// qDebug() << "用户点击了“取消”按钮";
// }

//警告对话框
QMessageBox::warning(this,"warning","警告");

});

13、布局设置–P23

①系统提供的布局控件

img

这4个为系统给我们提供的布局的控件,但是使用起来不是非常的灵活

②利用widget做布局

第二种布局方式是利用控件里的widget来做布局,在Containers中

img

在widget中的控件可以进行水平、垂直、栅格布局等操作,比较灵活。

再布局的同时我们需要灵活运用弹簧的特性让我们的布局更加的美观

注意:默认窗口的边框存在一定的距离 可以在layout中进行设置

image-20240731160617770

14、控件

①按钮组

QPushButton 常用按钮

QToolButton 工具按钮 用于显示图片,如图想显示文字,修改风格:toolButtonStyle , 凸起风格autoRaise

radioButton 单选按钮,设置默认 ui->rBtnMan->setChecked(true);

checkbox 多选按钮,监听状态,2 选中 1 半选 0 未选中

②QListWidget 列表容器

1
2
3
4
5
6
7
8
9
QListWidgetItem *item1 = new QListWidgetItem("12345");
QListWidgetItem *item2 = new QListWidgetItem("上山打老虎");
//设置居中显示
item1->setTextAlignment(Qt::AlignHCenter);
item2->setTextAlignment(Qt::AlignHCenter);

//加入到QListWidget
ui->listWidget->addItem(item1);
ui->listWidget->addItem(item2);

(可以利用addItems一次性添加整个诗内容)

③QTreeWidget 树控件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Widget::Widget(QWidget *parent): QWidget(parent) , ui(new Ui::Widget)
{
ui->setupUi(this);
//设置水平头
ui->treeWidget->setHeaderLabels(QStringList() << "英雄" << "英雄介绍");

//加载顶层节点
QTreeWidgetItem * liItem = new QTreeWidgetItem(QStringList() << "力量");
ui->treeWidget->addTopLevelItem(liItem);

//追加子节点
QTreeWidgetItem * Item1 = new QTreeWidgetItem(QStringList() << "zw" << "123");
QTreeWidgetItem * Item2 = new QTreeWidgetItem(QStringList() << "zz" << "456");
QTreeWidgetItem * Item3 = new QTreeWidgetItem(QStringList() << "ww" << "789");
liItem->addChild(Item1);
liItem->addChild(Item2);
liItem->addChild(Item3);
}

image-20240731164125070

④QTableWidget 表格控件

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
Widget::Widget(QWidget *parent): QWidget(parent) , ui(new Ui::Widget)
{
ui->setupUi(this);

//设置列数
ui->tableWidget->setColumnCount(3);
//设置水平表头
ui->tableWidget->setHorizontalHeaderLabels(QStringList() << "姓名" << "年龄" <<"性别");
//设置行数
ui->tableWidget->setRowCount(3);
//设置正文
QStringList name;
name <<"zw"<< "zz" << "ww";

QStringList sex;
sex << "男" << "女" << "男";
for(int i = 0; i < 3; i++)
{
int col = 0;
ui->tableWidget->setItem(i,col++,new QTableWidgetItem(name[i]));
ui->tableWidget->setItem(i,col++,new QTableWidgetItem(sex[i]));
//int转为QString类型
ui->tableWidget->setItem(i,col++,new QTableWidgetItem(QString::number(18+i)));
}

}

image-20240731165118253

⑤其他控件介绍

stackedWidget 栈控件

ui->stackedWidget->setCurrentIndex(1);

下拉框

ui->comboBox->addItem("奔驰");

QLabel 显示图片

ui->lbl_Image->setPixmap(QPixmap(":/Image/butterfly.png"))

QLabel显示动图 gif图片

ui->lbl_movie->setMovie(movie);

播放动图

movie->start();

15、自定义控件

①添加新文件

添加了.ui文件 即可通过这个ui文件对控件进行封装

image-20240801110348968

②进行设计自定义控件

image-20240801110619289

③将设计好的控件添加到主窗口中

选择 widget 控件 并右键其 选择 提升为

image-20240801110715728

④进行功能的设置

1
2
3
4
5
6
7
//设置数字加减 从而使得 滑动条移动
//使用函数指针 选择参数为(int)的函数
void(QSpinBox::*spSiganal)(int) = &QSpinBox::valueChanged;
connect(ui->spinBox,spSiganal,ui->horizontalSlider,&QSlider::setValue);

//设置滑动条移动 从而使得 数字发生改变
connect(ui->horizontalSlider,&QSlider::valueChanged,ui->spinBox,&QSpinBox::setValue);

image-20240801111632248

16、QT的鼠标事件

①鼠标的进入和离开事件

只需要重写父(QLabel)函数的 enterEvent(QEnterEvent * event)leaveEvent(QEvent *) 即可实现

1
2
3
4
5
6
7
8
9
10
11
//鼠标进入事件
void myLabel::enterEvent(QEnterEvent * event)
{
qDebug() << "鼠标进入";
}

//鼠标离开事件
void myLabel::leaveEvent(QEvent *)
{
qDebug() << "鼠标离开";
}

②鼠标的按下与释放

只需要重写父(QLabel)函数的 mousePressEvent(QMouseEvent *ev)mouseReleaseEventQMouseEvent *ev) 即可实现

1
2
3
4
5
6
7
8
9
10
//鼠标点击事件
void myLabel::mousePressEvent(QMouseEvent *ev)
{
qDebug() << "鼠标按下";
}
//鼠标释放事件
void myLabel::mouseReleaseEvent(QMouseEvent *ev)
{
qDebug() << "鼠标释放";
}

③鼠标的移动

只需要重写父函数(QLabel)的 mouseMoveEvent(QMouseEvent *ev)

1
2
3
4
5
//鼠标移动事件
void myLabel::mouseMoveEvent(QMouseEvent *ev)
{
qDebug() << "鼠标移动";
}

④如果需要得到鼠标的信息 则是需要使用其参数

1
2
QString str = QString("鼠标按下了x = %1, y = %2, globalX = %3, gloablY = %4").arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());
qDebug() << "鼠标按下" << str;

⑤判断左右按键

ev->button() 可以判断所有按键 Qt::LeftButton Qt::RightButton

1
2
3
4
if(ev->button() == Qt::LeftButton)
{
//执行操作
}

ev->buttons()判断组合按键 判断move时候的左右键 结合 & 操作符

1
2
3
4
if(ev->buttons() & Qt::LeftButton)
{
//执行操作
}

⑥设置鼠标的追踪状态 即可捕获非点击状态下的移动

1
2
3
4
myLabel::myLabel(QWidget *parent): QLabel{parent}
{
setMouseTracking(true);
}

17、定时器

①定时器事件

定时器事件 只需要重写 void timerEvent(QTimerEvent *) 即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget)
{
ui->setupUi(this);

//启动定时器 参数1是间隔单位是Ms
startTimer(1000);
}


//重写定时器的事件
void Widget::timerEvent(QTimerEvent *)
{
//定时器让区域内的内容 每次加1
ui->timer->setText(QString::number(num++));
}

②多个定时器

启动定时器 startTimer(1000);

启动定时器的返回值是 int 类型 记录的是启动某个事件的 id

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

void Widget::timerEvent(QTimerEvent *ev)
{
//定时器1 每隔一秒数字加1
if(ev->timerId() == id1)
{
ui->timer->setText(QString::number(num++));
}

if(ev->timerId() == id2)
{
//定时器2 每隔两秒数字加1
static int num2 = 1;
ui->timer2->setText(QString::number(num2++));
}
}

③定时器的第二种方式

1
2
3
4
5
6
7
8
9
10
11
12
13
Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget)
{
ui->setupUi(this);
//启动定时器的第二种方式
QTimer * timer = new QTimer(this);
//启动定时器
timer->start(500);
//绑定事件
connect(timer,&QTimer::timeout,[=](){
static int number = 1;
ui->timer3->setText(QString::number(number++));
});
}

18、事件分发器

用途:用于事件的分发

也可以做拦截操作,不建议

bool event( QEvent * e);

返回值 如果是true 代表用户处理这个事件,不向下分发了

e->type() == 鼠标按下 …

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//通过event事件分发器 拦截 鼠标按下事件
bool event(QEvent * e)
{
//拦截 鼠标按下事件
if(e->type() == QEvent::MouseButtonPress)
{
//将QEvent类型的数据e 强制转换为 QMouseEvent类型的数据ev
QMouseEvent *ev = static_cast<QMouseEvent *>(e);
QString str = QString("QEvent 鼠标按下了x = %1, y = %2, globalX = %3, gloablY = %4").arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());
qDebug() << "QEvent 的 鼠标按下" << str;
return true; // true代表用户自己处理了 不向下分发
}

//未拦截的事件 会自动交给父类处理(默认处理)
//return event(e);
}

19、事件过滤器

在程序将时间分发到事件分发器前,可以利用 过滤器 做拦截

①步骤如下:

(1)给控件安装事件过滤器

ui->label->installEventFilter(this);

(2)重写 eventFilter函数 (obj , e)

eventFilter(QObject *obj, QEvent * e)

拦截某个事件后 原本的处理就失效 转而实现拦截器中的事件处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//重写事件过滤器(拦截了鼠标点击的事件)
bool Widget::eventFilter(QObject *obj, QEvent * e)
{
if(obj == ui->label)//判断是哪个部件的过滤器
{
if(e->type() == QEvent::MouseButtonPress)//判断是什么条件的过滤器
{
QMouseEvent *ev = static_cast<QMouseEvent *>(e);
QString str = QString("事件过滤器中的 鼠标按下了x = %1, y = %2, globalX = %3, gloablY = %4").arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());
qDebug() << "事件过滤器中的 鼠标按下" << str;
return true;// true代表用户自己处理了 不向下分发
}
}
//其他的默认处理
return QWidget::eventFilter(obj,e);//未拦截的事件 会自动交给父类处理(默认处理)
}

20、绘图事件

①先重写绘图函数

paintEvent(QPaintEvent *)

②声明画家对象

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
//绘图事件
void Widget::paintEvent(QPaintEvent *)
{
// 需要先包含#include <QPainter> //画家类

//画家对象
QPainter painter(this);//在当前窗口下绘画

//画笔对象
QPen pen(QColor(255,0,0));
//让画家 使用这个笔
painter.setPen(pen);

//画刷对象
QBrush brush(QColor(0,255,0));
//让画家使用这个画刷
painter.setBrush(brush);

//画线
painter.drawLine(QPoint(0,0),QPoint(100,100));
//椭圆
painter.drawEllipse(QPoint(100,100),50,50);
//画矩形
painter.drawRect(QRect(20,20,50,50));
//画文字
painter.drawText(QRect(10,200,100,50),"hello");
}

③绘图的高级设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//绘图事件
void Widget::paintEvent(QPaintEvent *)
{
// 需要先包含#include <QPainter> //画家类
QPainter painter(this);//在当前窗口下绘画

// painter.drawEllipse(QPoint(100,100),50,50);
// //设置抗锯齿(效率低)
// painter.setRenderHint(QPainter::Antialiasing);
// //画圆
// painter.drawEllipse(QPoint(200,100),50,50);

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

④手动调用绘图事件

利用画家 画 资源图片

1
2
QPainter painter(this);//在当前窗口下绘画
painter.drawPixmap(0,0,QPixmap(":/image/lenna.jpg"));

如果需要手动调用绘图事件 则使用update进行更新

⑤绘图设备

可以将绘制的画面 保存在本地

QImageQPixmap 的功能类似

但是QImage 的像素更加清晰 经过了增强

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget)
{
ui->setupUi(this);
//pixmap绘图设备
QPixmap pix(300,300);

//声明画家对象
QPainter painter(&pix);
painter.setPen(QPen(Qt::green));
painter.drawEllipse(QPoint(150,150),100,100);

//保存
pix.save("D:\\pix.png");
}

QPicture绘图设备 可以 记录和重现 绘图指令(主要是用来记录绘图的步骤的)

21、QFile文件操作

①读文件操作

QFile 默认读取的格式是 UTF-8

格式转换为 GBK 格式

QString content = QString::fromLocal8Bit(array);

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
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);

//点击按钮 弹出选取文件的对话框

connect(ui->pushButton,&QPushButton::clicked,[=](){
QString path = QFileDialog::getOpenFileName(this,"打开文件","C:\\Users\\zw\\Desktop");
ui->lineEdit->setText(path);


//指定路径读取内容 放在textEDit中
QFile file(path);
//QFile默认读取的格式是UTF-8
//设置打开方式 只读
file.open(QIODevice::ReadOnly);
QByteArray array = file.readAll();

// ui->textEdit->setText(array);

//改成这样可以读取gbk格式
QString content = QString::fromLocal8Bit(array);
ui->textEdit->setText(content);
});

//关闭文件对象
file.close();

}

②写文件操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);

//点击按钮 弹出选取文件的对话框

connect(ui->pushButton,&QPushButton::clicked,[=](){
QString path = QFileDialog::getOpenFileName(this,"打开文件","C:\\Users\\zw\\Desktop");

//指定路径读取内容 放在textEDit中
QFile file(path);

//进行写操作
file.open(QIODevice::Append);
file.write("123456789");
file.close();

});

③QFileInfo 文件信息类

1
2
3
4
5
6
7
8
//文件信息类
QFileInfo info(path);
qDebug() << "大小:" << info.size();
qDebug() << "后缀名:" << info.suffix();
qDebug() << "文件名称:" << info.fileName();
qDebug() << "文件路径:" << info.filePath();
qDebug() << "创建日期:" << info.birthTime().toString("yyyy/MM/dd hh:mm:ss");
qDebug() << "修改日期:" << info.lastModified().toString("yyyy/MM/dd hh:mm:ss");

22、QT与Halcon的类型转换

①Halcon类型 —> QT类型

(1)字符串

1
2
std::string str = (std::string)hv_DecodedDataStrings[0].S();
QString ans = QString::fromStdString(str);

(2)Gray灰度图像

1
2
3
4
5
6
7
8
9
//抓取图像
GrabImageAsync(&ho_Image, hv_AcqHandle, -1);

//将这个灰度图像 转为QT中的QPixmap
GetImagePointer1(ho_Image, &hv_Pointer, &hv_Type, &hv_Width, &hv_Height);
BYTE* p = (BYTE*)hv_Pointer[0].L();
QImage image((uchar*)p, hv_Width, hv_Height, QImage::Format_Grayscale8);
QPixmap pixmap = QPixmap::fromImage(image);
ui.label->setPixmap(pixmap);

(3)RGB彩色图

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
//抓取图像
GrabImageAsync(&ho_Image, hv_AcqHandle, -1);

//将这个rgb彩色图像 转为QT中的QPixmap
GetImagePointer3(ho_Image, &hv_PointerRed, &hv_PointerGreen, &hv_PointerBlue,&hv_Type1, &hv_Width1, &hv_Height1);

//得到图片的宽和高
int width = hv_Width1[0].I();
int height = hv_Height1[0].I();

//得到图片的rgb数据
BYTE* pRed = (BYTE*)hv_PointerRed[0].L();
BYTE* pGreen = (BYTE*)hv_PointerGreen[0].L();
BYTE* pBlue = (BYTE*)hv_PointerBlue[0].L();
//正确的开辟数组的大小 是 width * height * 3
BYTE* ImageRGB = new BYTE[width * height * 3];
//对ImageRGB正确赋值
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
ImageRGB[i * 3 * width + 3 * j] = pRed[i * width + j];
ImageRGB[i * 3 * width + 3 * j + 1] = pGreen[i * width + j];
ImageRGB[i * 3 * width + 3 * j + 2] = pBlue[i * width + j];
}
}

//转为Image和Pixmap数据类型
QImage* tempImage = new QImage(ImageRGB, width, height, QImage::Format_RGB888);
QPixmap pixmap = QPixmap::fromImage(*tempImage);
ui.label->setPixmap(pixmap);

23、数据异常

当出现数据异常的时候 大概率是因为某个数据不存在导致的

1
if (hv_DecodedDataStrings.Length() > 0)

直接使用 Length() 判断长度不为0的情况


文章作者: Yolo
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Yolo !
评论
  目录