前言
勇哥对于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
一个信号可以连接多个槽函数
多个信号可以连接同一个槽函数
信号和槽函数的个数必须一一对应
信号的参数个数 可以大于槽函数的参数个数 ,反之不可以

