<1>qt打包教程(不安装qt也可以用)

https://blog.csdn.net/u014453443/article/details/85837138?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param

<2>qt常用的类型转换

(1)字节数组(char、uint8、int8)转QByteArray类
(2)QByteArray类转字节数组(char
、uint8、int8)
(3)字节数组转hex字符串
(4)字节数组(char、uint8、int8)转QString
(5)QString转字节数组(char
、uint8、int8)
(6)单个数字、字符串,互转
(7)QByteArray与QString互转

QByteArray类提供了类似数组的功能,但功能更强大,常用函数:
只读元素at(n)、读写元素[n]、追加元素append(可以追加QString、char*、char、QByteArray)、迭代器、元素存储区指针data()

1、字节数组转QByteArray类(字节数组是指uint8、int8、char的数组)
直接使用QByteArray的构造函数即可,

  1. 1. const char *str="abcde";
  2. 2. char u8_arr[3]={0xa1,0xC2,0x3E};
  3. 3. QByteArray qa1(str); //qa1,qa2为两个QBytearray类型的变量
  4. 4. QByteArray qa2(u8_arr,3);

QByteArray 的元素存储地址可以通过成员函数data()获得,使用*data可以访问QByteArray 的元素
注意:如果数组中有’\0’,那么构造QByteArray对象时,碰到数组的\0构造就停止了

2、QByteArray类转字节数组(char、uint8、int8)
直接*使用QByteArray的成员函数
即可

  1. 1. QByteArray ba("abcd");
  2. 2. char *pArr = ba.data();

3、字节数组转hex字符串(字节数组是指uint8、int8的数组)

  1. 1. uint8 u8_arr[3]={0xF5,0x07,0xa5};
  2. 2. QByteArray qa2(u8_arr,3);//中转一下
  3. 3. QString qstr(qa2.toHex());
  4. 4. qDebug()<<qstr.toUpper();//输出字符串:F507A5

QByteArray的toHex()的返回值仍为QByteArray型,因为每一个字节都会变成2个hex字符,所以返回的QByteArray的长度是原来的两倍

4、字节数组(char、uint8、int8)转QString
如果字节数组有字符串结尾符\0,则可以直接使用QString的构造函数构造QString对象。
如果字节数组没有\0,*可以先把字节数组转成QByteArray,然后用QByteArray构造QString
,参考第1条

5、QString转字节数组(char、uint8、int8)
QString转成了char
,也就相当于转成了字节数组,
参考:https://blog.csdn.net/lu_embedded/article/details/52465203
这篇文章提到了两种方法:
(1)QString中无中文:

  1. 1. QString str;
  2. 2. char *ch;
  3. 3. QByteArray ba = str.toLatin1(); // 这一行不可少
  4. 4. ch=ba.data();//不允许这样用:ch=str.toLatin1().data();

QString中有中文:避免乱码,需要使用QTextCodec

  1. 1. #include <QTextCodec>
  2. 2. QTextCodec::setCodecForTr(QTextCodec::codecForName("GBK"));
  3. 3. QTextCodec::setCodecForLocale(QTextCodec::codecForName("GBK"));
  4. 4. QByteArray ba = str.toLocal8Bit(); // toLocal8Bit 支持中文

注意:QString的toLatin1函数返回的QByteArray是带\0的
第三行不可少,如果直接这样转:ch=str.toLatin1().data(),会出错。原因应该是这样的:toLatin1的返回值是值传递,而不是引用传递,使用值传递来传返回值,返回值是位于内存栈上的,语句结束之后,返回值作为一个临时局部变量,被出栈,这时再使用.data()取指针,指针指向的位置已被出栈,不存在了,为了避免这种情况,就是把toLatin1的返回值使用局部变量甚至局部静态变量接收过来,例如这里的ba变量,toLatin1的返回值出栈消失了,但是ba还在,所以再使用ba.data()就可以获取一个有效指针。
(2)先将 QString 转为标准库中的 string 类型,然后将 string 转为 char *

  1. 1. QString filename;
  2. 2. std::string str = filename.toStdString();
  3. 3. const char* ch = str.c_str();

6、单个数字、字符串,互转
(1)数字转字符串两种方法:

  1. 1. int num = 1000;// 1000 = 0x03E8;
  2. 2. QString str = QString("%1").arg(num,4,16,(QChar)'0').toUpper();

这种方法可以把数组转为16进制样式”03E8”、10进制样式的字符串”1000”、8进制样式等
② QString::number(double n, char format = ‘g’, int precision = 6),
如QString str = QString::number(1000);//str=”1000”
(2)字符串转数字:
使用QString的成员函数即可:toInt、toDouble
字符串的样式可通过形参指定,如

  1. 1. QString str = "123";
  2. 2. bool OK;
  3. 3. int a = str.toInt(&OK, 10);// a=123,OK=true
  4. 4. int b = str.toInt(&OK, 16);// b=0x123,OK=true

7、QString转QByteArray方法

  1. QString str("hello");
  2. QByteArray bytes = str.toUtf8(); // QString转QByteArray方法1
  3. QString str("hello");
  4. QByteArray bytes = str.toLatin1(); // QString转QByteArray方法2


QByteArray转QString方法

  1. QByteArray bytes("hello world");
  2. QString string = bytes; // QByteArray转QString方法1
  3. QByteArray bytes("hello world");
  4. QString string;
  5. string.prepend(bytes); // QByteArray转QString方法2
  6. qDebug() << string;

<3>透明按钮

QPushButton *bt =new QPushButton(this);
bt->setText(“ok”);
bt->move(200,100);
bt->setFlat(true);

<4>通过connect函数理解信号槽

connect函数的理解

  1. connect(sender, signal,
  2. receiver, slottype);

sender:发出信号的对象
signal:发出的信号
receiver:接收信号的对象
slot:该对象接收到信号后的操作(执行的函数)
type:连接种类模式选择

信号槽,实际就是观察者模式。事件发生后,比如按钮检测到自己被点击了一下,它就会发出一个信号signal。这种发出类似广播。如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,意思是,用自己的一个函数(成为槽(slot))来处理这个信号。也就是说,当信号发出时,被连接的槽函数会自动被回调。这就类似观察者模式:当发生了感兴趣的事件,某一个操作就会被自动触发。

<5>拓展补充

在编译共享库时,必须将其标记为导出。为了在客户端使用共享库,一些平台可能需要一个特殊的导入声明。

Qt 提供了两个特殊的宏:

  • Q_DECL_EXPORT:当编译共享库时,必须将其添加到使用的符号声明。
  • Q_DECL_IMPORT:当编译一个(使用了该共享库)客户端时,必须将其添加到使用的符号声明。

补充:报错之一——LNK2019 解决办法
编译的时候,出现这样的情况,如图:
(moc_widget.obj👎 error: LNK2019: 无法解析的外部符号 “private: void cdecl Widget::on_pushButton_3_clicked(void)” (?on_pushButton_3_clicked@Widget@@AEAAXXZ),该符号在函数 “private: static void cdecl Widget::qt_static_metacall(class QObject ,enum QMetaObject::Call,int,void *)” (?qt_static_metacall@Widget@@CAXPEAVQObject@@W4Call@QMetaObject@@HPEAPEAX@Z) 中被引用)
Qt 知识积累 - 图1
这个问题大概率是你的槽函数的声明和实现没有匹配上,可以先:

1.进入文件夹,删除类似这样的文件夹.重新进行编译.

Qt 知识积累 - 图2

2.项目上面右击,清除,执行Qmake,构建.再来.

3.这是我这次遇到的情况,我之前直接通过按钮右击,转到槽,准备写槽函数,但是发现我的按钮没有命名(默认pushButton),然后我就直接删掉槽函数的实现部分,但是忘掉即使是通过转到槽这样的方式来写槽函数,在头文件中也会生成相应的声明,这时候去头文件把之前的那个声明删除就可以了.

牢记:槽函数的声明和实现要同生死共存亡.

<6>自定义信号槽

只有继承了QObject类的类,才具有信号槽的能力。凡是QObject类(不管是直接子类还是间接子类),都应该在第一行代码写上Q_OBJECT。不管是不是使用信号槽,都应该添加这个宏
写法如下:
(1)头文件中声明信号
signals:
void Mysignal(); //返回值信号
(2)如何发送信号
connect(returnButton,&QPushButton::clicked,this,&MainWindow2::Sendslot);

void MainWindow2::Sendslot() //点击按钮,发送信号
{
emit Mysignal();
}
(3)处理子窗口的信号(这里以主窗口处理子窗口信号为例)
connect(&w2,&MainWindow2::Mysignal,this,&Widget::dealmainwindow2);

头文件中:signals:一个个函数名,返回值是 void(因为无法获得信号的返回值,所以也就无需返回任何值),参数是该类需要让外界知道的数据。
emit 是 Qt 对 C++ 的扩展,是一个关键字(其实也是一个宏)。emit 的含义是发出,即发出信号

<7>qt 中 QPixmap 类的使用及用 QLabel 显示图像

一般方法(图片显示于label)
ui->label->setPixmap(QPixmap::fromImage(image));
QLabel缩放时维持图像宽高比例不变:
ui->label>setPixmap(QPixmap::fromImage(image).scaled(ui->label->size(),
Qt::KeepAspectRatio,Qt::SmoothTransformation));
若要图像始终填充满QLabel,需要如下语句:
ui->label->setScaledContents(true);

补充: 利用 QLabel 显示 Mat 图像的一个方法为:(with OpenCV 3)
cv::Mat mat = cv::imread(“c:/dev/test.jpg”);
QImage image(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
ui->label->setPixmap(QPixmap::fromImage(image.rgbSwapped()));

<8>QT中定时器的使用方法

先创建一个QTimer对象,再将信号timeout()与相应的槽函数相连,然后调用start()函数。接下来,每隔一段时间,定时器便会发出一次timeout()信号。

  1. QTimer *timer = new QTimer(this);
  2. connect(timer, SIGNAL(timeout()), this, SLOT(update()));
  3. timer->start(1000);
  4. //或写成:
  5. if (myTimer->isActive() == false)
  6. {
  7. myTimer->start(100);
  8. }
  9. timer->stop(); //关闭定时器

<9>QWidget中信号槽用法

以下几种写法均可
(1)connect(ui->Open,SIGNAL(clicked()),this,SLOT(on_Open_clicked()));
(2)connect(ui->btn_open,&QPushButton::clicked,this,&serial::btn_open_port);
(3) btnClose = new QPushButton(this);
connect(btnClose,SIGNAL(clicked()),this,SLOT(close()));
总结:参数一写组件对象名(有ui->和直接定义两种写法)
参数二信号有不同写法
参数三this:在这个界面对应的类触发
参数四槽函数有不同写法(写成槽函数形式/写成某个类的一个方法均可)

注意:qt自带有一些定义好的槽函数,不需要在头文件中声明便可直接用,比如close(),hide()
对一个窗体调用close函数后,如果再调用show(),这个窗体又会被显示出来。

<10>多窗口切换

多窗口切换会用到自定义信号(见前文)
主窗口代码:
//处理子窗口的信号
connect(&w3,&Wave::Wavesignal,this,&Widget::dealwavewindow);

void Widget::dealmainwindow2()
{
//按钮回到主窗口
w2.hide();
this->show();
}
void Widget::showMainwindow2()
{
//按钮显示2窗口
w2.show();
}

解决中文乱码:
使用QString::fromLocal8Bit(“你好”);
使用QStringLiteral(“中国”);

<11>qt画图函数

paintEvent(QPaintEvent*)函数是QWidget类中的虚函数,用于ui的绘制,会在多种情况下被其他函数自动调用,比如update()时