前言
勇哥对于C语言,C++早些年有一些接触,这个系列贴子就记载一下C++应用框架的学习经验。 在写程序时,UI、基础类库、应用程序框架对于vc来讲,只能依靠MFC和QT了。 勇哥对MFC有很强的抵触,它长得丑,很多地方反人类,唯一的好处是VC原生自带的。 所以还是先研究一下QT,再研究MFC吧,否则会带了很大的挫折感。 另外,采用vc++进行.net开发,即托管方式开发,可以使用WPF做界面,在有些公司也是被采用的方案, 这方面勇哥是全盲,也要抓紧研究一下。 所有将要做的这一切,都是想为OpenCV服务! 加油。。。
第一篇笔记开始研究QT,包含下面的内容:
1、创建第一个Qt程序
2、熟悉按钮控件常用API
3、对象树的基本概念
4、Qt中的坐标系统
5、信号和槽的基本使用以及拓展
6、opencv读取显示图片
QT的模块,我们后续先研究点有用的,包括:Qt Widgets, Qt Core, Qt GUI, Qt Network。
下图是QTv5版的模块。如果是v5版以下,Qt Widgets是被包含在GUI中的。

先把练习程序放上来。
它的工程是这样的:

很简单,图片是opencv读入,并用QT控件显示的。
几个按钮是代码创建的,重点是熟悉信号槽的用法,它的作用就是用来完成类似C#中的按钮的事件。

先提供源代码。
MyButton.h
#pragma once
#include <QWidget>
#include <qpushbutton.h>
class MyButton : public QPushButton
{
Q_OBJECT
public:
MyButton(QWidget *parent);
~MyButton();
};QtForOpencv.h
#pragma once
#pragma execution_character_set("utf-8")
#include <QtWidgets/QWidget>
#include "ui_QtForOpencv.h"
#include <QLabel>
#include "student.h"
#include "teacher.h"
class QtForOpencv : public QWidget
{
Q_OBJECT
public:
QtForOpencv(QWidget *parent = Q_NULLPTR);
~QtForOpencv();
void clickfun();
void classIsOver(); //下课了(无参数)
void classIsOver2(QString name); //下课了(有参数)
void btn1Fun();
private:
Ui::QtForOpencvClass ui;
public:
QLabel* imgLabel;
Teacher* tc;
Student* st;
};student.h
#pragma once
#pragma execution_character_set("utf-8")
#include <QObject>
class Student : public QObject
{
Q_OBJECT
public:
Student(QObject *parent);
~Student();
public slots:
//低版本写在这里,高版本直接写到public下面。
//槽函数返回void,它需要声明也需要实现。
//槽函数可以有参数,可以发生重载
void eat();
void eat(QString name); //有参数的槽函数
};teacher.h
#pragma once
#include <QObject>
class Teacher : public QObject
{
Q_OBJECT
public:
Teacher(QObject *parent);
~Teacher();
signals:
//信号必须void,可以有参数。
//信号只需要声明,不需要实现。
void hugry();
void hugry(QString name);
};main.cpp
#include "QtForOpencv.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QtForOpencv w;
w.show();
return a.exec();
}MyButton.cpp
#include "MyButton.h"
#include <QDebug.h>
MyButton::MyButton(QWidget *parent)
: QPushButton(parent)
{
}
MyButton::~MyButton()
{
qDebug() << QStringLiteral("MyButton的析构");
}QtForOpencv.cpp
#include "QtForOpencv.h"
#include <opencv2\opencv.hpp>
#include <opencv2\core.hpp>
#include <opencv2\imgcodecs.hpp>
#include <opencv2\imgproc.hpp>
#include <qpushbutton.h>
#include "MyButton.h"
#include <QDebug.h>
#include <qmessagebox.h>
using namespace cv;
using namespace std;
QtForOpencv::QtForOpencv(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
QPushButton* btn = new QPushButton();
btn->setParent(this);
btn->setText(QStringLiteral("push按钮1"));
//按下后执行btn1Fun,弹出一个messagebox
connect(btn, &QPushButton::clicked, this, &QtForOpencv::btn1Fun);
QPushButton* btn2 = new QPushButton(QStringLiteral("push按钮2"), this);
resize(600, 400);
btn2->move(100, 100);
btn2->resize(150, 50);
//按下后直接关闭当前窗口
connect(btn2, &MyButton::clicked, this, &QtForOpencv::close);
setWindowTitle(QStringLiteral("这是父窗口的标题"));
setFixedSize(600, 600);
MyButton* btn3 = new MyButton(this);
btn3->setText(QStringLiteral("自定义按钮"));
btn3->move(100, 200);
//信号发送者,发送的信号,信号的接收者,处理的槽函数
//按下后输出一句话在调试窗口
connect(btn3, &MyButton::clicked, this, &QtForOpencv::clickfun);
//自动定义信号和槽函数
//两个类 Teacher,Student类
//下课后, 老师tc发一个信号 “饿了”
//学生st响应这个信号,处理槽函数 “请客吃饭 ”
tc = new Teacher(this);
st = new Student(this);
//下面是信号与槽函数没有参数没有重载情况下的写法
//connect(tc, &Teacher::hugry, st, &Student::eat);
//classIsOver();
//下面是信号与槽函数都有重载的情况下的写法
void(Teacher:: *tSignal)(QString) = &Teacher::hugry;
void(Student:: *sSignal)(QString) = &Student::eat;
connect(tc, tSignal, st, sSignal);
classIsOver2("东莞烧鸭");
//演示opencv载入图片并显示
Mat src = imread("e:/1.jpg"); // 读取图片
if (src.empty()) {
printf("could not load image...\n");
}
cvtColor(src, src, COLOR_BGR2RGB); //BGR图片装换成RGB图片
cv::resize(src, src, Size(300, 300)); // 修改图片大小
imgLabel = new QLabel(this);
imgLabel->setText(QStringLiteral("原图"));
imgLabel->move(200, 200);
QImage showImg = QImage((const unsigned char*)(src.data), src.rows, src.cols, QImage::Format_RGB888);
imgLabel->setPixmap(QPixmap::fromImage(showImg));
imgLabel->show(); // 在qt界面显示图片
waitKey(0);
}
void QtForOpencv::btn1Fun()
{
//演示了QMessageBox的用法
qDebug() << QStringLiteral("按了btn1按钮");
QMessageBox::StandardButton rb = QMessageBox::information(NULL, "Title", "按钮一被按下了!",
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
if (rb == QMessageBox::Yes)
{
QMessageBox::aboutQt(NULL, "About Qt");
}
}
void QtForOpencv::clickfun()
{
qDebug() << QStringLiteral("按了btn3按钮");
}
QtForOpencv::~QtForOpencv()
{
qDebug() << QStringLiteral("QtForOpencv析构");
}
void QtForOpencv::classIsOver()
{
//触发老师饿了的信号
//这个信号是自定义信号,触发自定义的信号关键字是emit
emit tc->hugry();
}
void QtForOpencv::classIsOver2(QString name)
{
//触发老师饿了的信号
//这个信号是自定义信号,触发自定义的信号关键字是emit
emit tc->hugry("东莞烧鸭");
}student.cpp
#include "student.h"
#include <Qdebug.h>
Student::Student(QObject *parent)
: QObject(parent)
{
}
Student::~Student()
{
}
void Student::eat()
{
qDebug() << QStringLiteral("学生收到了,准备请老师吃饭");
}
void Student::eat(QString name)
{
//注意下面两句的区别
//直接引号的字符串是char*, 第二句是把QString转为char*
//qDebug() << QStringLiteral("学生收到了,准备请老师吃饭: ") << name;
qDebug() << "学生收到了,准备请老师吃饭: " << name.toUtf8().data();
}teacher.cpp
#include "teacher.h"
Teacher::Teacher(QObject *parent)
: QObject(parent)
{
}
Teacher::~Teacher()
{
}代码里的一些知识点:
Main函数
QApplication a 应用程序对象 有且仅有一个
a.exec() 进行消息循环 阻塞
MyWidget w 窗口对象
默认不会弹出窗口 想要显示窗口 需要调用 show
QPushButton
QPushButton * btn = new QPushButton;
btn->setParent(this) 设置父亲
btn->setText (“aaa”)
btn->move( x, y)
重置窗口大小 resize(w,h)
重置窗口标题 setWindowTitle(“aaaa”)
设置固定窗口大小 setFixedSize(w,h)
对象树
所有new出来的对象 不用管释放
原因 children表中的对象会在窗口关闭后进行自动释放
Qt中的坐标系
x正向 →
y正向 ↓
Qt中的信号和槽
需求 点击按钮 关闭窗口
connect( 信号发送者,发送的信号,信号接受者,处理槽函数 )
优点 松散耦合
Qt中的自定义信号和槽
自定义信号
返回值 void
需要声明 不需要实现
可以有参数
自定义槽函数
返回值void
需要声明 需要实现
可以有参数
触发自定义的信号
emit
当自定义信号和槽 出现重载时候,原先写法失效,因为执行的函数地址不明确
解决方法: 利用函数指针 来明确指向哪个函数的地址
QString转char* toUtf8 转 QBtyeArray 类型 在利用data 转成char*
信号和槽的拓展
信号是可以连接信号的
信号和槽可以断开 disconnect
一个信号可以连接多个槽函数
多个信号可以连接同一个槽函数
信号和槽函数的个数必须一一对应
信号的参数个数 可以大于槽函数的参数个数 ,反之不可以


少有人走的路



















