-
- 一 QT定时器
- 二 QT界面布局
- 三 QT5+VS2013程序发布
- 四 int与QString相互转化
- 五 设置打开文件路径+读取该目录下的所有图片
- 六 界面与对话框的退出
- 七 子窗口访问父窗口的成员函数与成员变量
- 八 删除文件夹内或者文件夹内的所有文件
- 九 如何在lineEdit中输出int类型的变量
- 十 Mat与QImage相互转化的函数
- 十一 QGraphicsView类的简单用法
- 十二 关于QT多线程
- 十三 从主窗口启动子窗口
- 十四 QMessageBox消息窗口的调用
- 十五 vs2015+QT5添加多个子对话框
- 十六 QT中如何显示调试界面
- 十七 QT如何处理密集型耗时的事情(频繁调用QApplication::processEvents)
一 QT定时器
Qt有两种定时器:一种是QObject类的定时器,另一种是QTimer类的定时器。
1.1 QObject类的定时器:
QObject类提供了一个基本的定时器,通过函数startTimer()来启动,通过killTimer()来结束,通过QTimerEvent来处理定时器事件。
三个主要函数:
①stratTimer(int interval,Qt::TimerType timerType=Qt::CoarseTimer);
②void killTimer(int id);
③void QObject::timerEvent(QTimer *event);
startTimer(int interval)启动一个时间间隔为interval毫秒的定时器,返回一个定时器标识符,如果未能启动成功,则返回0。
该定时器只能使用killTime()来杀死,killTimer(int id)通过定时器标识符来杀死定时器。
如果有多个定时器,可以通过QTimerEvent::timerId()来获取已经启动的定时器标识符。
1.1.1 使用的示例代码:
int m_timerId; //定时器ID 在头文件中定义
void DynamicTrackDlg::on_btnToTrack_clicked()
{
//启动定时器,设置检查定时器的时间间隔,单位ms
m_timerId = startTimer(20);
}
void DynamicTrackDlg::timerEvent(QTimerEvent *event)
{
if (event->timerId() == m_timerId)
{
...
killTimer(m_timerId); //关闭定时器
}
}
1.2 QTimer类的定时器
QTimer类定时器是QObject类定时器的扩展版或者说升级版,因为它可以提供更多的功能。比如说,它支持单次触发和多次触发。
使用QTimer类定时器的步骤:
- 创建一个QTimer定时器实例:QTimer *timer = new QTimer(this);
- 连接超时信号与槽:connect(timer, SIGNAL(timeout()), this, SLOT(testFunc()));
- 启动定时器start();
- 适时关闭定时器:stop();
- 删除定时器实例:delete timer;
二 QT界面布局
2.1 如何将布局上下按比例设置大小?
方法:先点全选,右侧的布局“layoutRowStretch”and“layoutColumnStretch”进行设置即可。
三 QT5+VS2013程序发布
3.1 骤如下:
- 首先,在VS界面选择Release+x64(你要发布32,则选择win32,前提是你装了32位的 Qt)。
- 生成-重新生成解决方案。
- 打开-文件夹Release文件,选择生成的exe文件。
- 桌面新建文件,并将exe文件拷贝至此。
使用Qt自带工具查找dll等文件。
①.将Qt安装目录的bin的路径添加到环境变量
我的Qt-bin路径
添加变量:计算机-右键-属性-高级系统设置-环境变量-系统变量-path-编辑(记得变 量之间用分号隔开);
②.点击开始-cmd-回车进入命令提示符,使用cd命令进入刚刚创建的A文件夹
③.现在开始关键一步:接着输入:windeployqt xx.exe (xx为exe文件名)。
现在A文件夹下会出现许多文件,把A文件夹拷贝给其他人的电脑就可用了。
四 int与QString相互转化
4.1 int转化为QString
//头文件
#include <sstream>
#include<QString>
//函数实现
int imgNumber=50;
stringstream NextImg;
NextImg << imgNumber;
ui.editImgNum->setText(NextImg.str().c_str()); // void setText(const QString &);
4.2 将QString转化为Int
//头文件
#include<QString>
//函数实现
QString mString = ui.lineEditPixelThreshold->text();
int nPixelThreshold = mString.toInt();
五 设置打开文件路径+读取该目录下的所有图片
5.1 设置打开文件路径的程序中无中文时
前提:在该工程文件下,先新建一个文件夹image,在其下新建两个文件夹 L和R。
//头文件
#include<QFileDialog>
public slots:
void on_setPathButton_clicked(); //此为ui中设置打开文件路径(pushButton)中的按钮名;
//函数实现
void on_setPathButton_clicked()
{
//设置左右相机拍摄图像的上一级目录
QString imgPath = QFileDialog::getExistingDirectory(this,“Set Path”,"./image",QFileDialog::Option::ShowDirsOnly);
//确定左右图像路径
QString imgPathL = imgPath + "/L";
QString imgPathR = imgPath + "/R";
//如果此时需要将界面中的下一个按钮设置为可用
ui.btnOpenCams->setEnabled(true); //此处 btnOpenCams为打开相机的pushButton; 同时需要将ui中的btnOpenCams属性的enabled后面的勾号去掉。
}
5.2 设置打开文件路径的程序中有中文时
5.2.1 前提:
- 在该工程文件下,先新建一个文件夹ImgFiles。
- 在项目中包含头文件:GBK.h
- 做好的界面如下:
5.2.2 代码示例:
//头文件中
#include<QFileDialog>
#include<GBK.h>
public slots:
void on_setPathButton_clicked(); //此为ui中设置打开文件路径(pushButton)中的按钮名;
//函数实现:
void on_setPathButton_clicked()
{
//设置图像的上一级目录
QString imgPath = QFileDialog::getExistingDirectory(this, GBK::ToUnicode("设置图像 打开路径"), "D:/ImgFiles/", QFileDialog::Option::ShowDirsOnly);
//读取该文件夹下的所有图片
QDir dir(imgPath);
QStringList nameFilters;
nameFilters << "*.jpg"; //此处根据文件目录下存放的图片格式来定 .bmp 等
dir.setNameFilters(nameFilters);
dir.setSorting(QDir::Name);
//获取路径中图像名列表
imgNameList = dir.entryList();
QString tem = imgPath;
tem = tem + "/";
//imgNameList存放着每张图片的路径
for (int i = 0; i < imgNameList.size();i++)
{
imgNameList[i].prepend(tem); //pretend()是插入的意思。
}
//将图片总数显示出来
std::stringstream str;
str << imgNameList.size();
ui.editTotalNum->setText(str.str().c_str()); //editTotalNum为对应的lineEdit名
//如果此时需要将界面中的下一个按钮设置为可用
ui.btnReadImg->setEnabled(true); //此处btnReadImg 为读取图片的pushButton; 同时需要将ui中的btnReadImg 属性的enabled后面的勾号去掉。
}
5.3 读取该路径下的图片
5.3.1 在5.2的基础上
//头文件
#include<QPixel>
public slots:
//读取当前图片
void on_btnReadImg_clicked();
public:
//待检测图像名列表
QStringList imgNameList;
//用于存储当前显示图像的序号
int imgNum;
//存储当前显示图像pixmap
QPixmap *pixmap;
//当前图像的宽高
int imgWidth;
int imgHeight;
//存储当前待检测图像的Mat
Mat drawImg;//三通道
Mat grayImg;//单通道图像
// 函数实现
void 类名::on_btnReadImg_clicked()
{
pixmap = new QPixmap(imgNameList[imgNum]);
ui.ImgLabel ->setPixmap(*pixmap); //ImgLabel为ui中图片显示的控件名
imgWidth = pixmap->width(); //读取图像宽度
imgHeight = pixmap->height(); //读取图像高度
drawImg = cv::imread(imgNameList[imgNum].toStdString(), CV_LOAD_IMAGE_COLOR); //转化为Mat
cvtColor(drawImg, grayImg, CV_BGR2GRAY);
stringstream PicNum;
int PicNumber = imgNum + 1;
PicNum << PicNumber;
ui.editImgNum->setText(PicNum.str().c_str()); //显示当前图片序号
ui.btnNextImg->setEnabled(true); //开启读取下一张图片
ui.btnToDetectSampleImgs->setEnabled(true); //开启检测图片按钮
}
5.3.2 读取下一张图片的按钮
//头文件
#include<QPixel>
public slots:
//下一张图片
void on_btnNextImg_clicked();
//函数实现
void 类名::on_btnNextImg_clicked()
{
//清空显示结果的lineEdit内容
ui.editResult->clear();
imgNum++;
//和读取图片的过程相似
pixmap = new QPixmap(imgNameList[imgNum]);
ui.ImgLabel->setPixmap(*pixmap);
imgWidth = pixmap->width();
imgHeight = pixmap->height();
drawImg = cv::imread(imgNameList[imgNum].toStdString(), CV_LOAD_IMAGE_COLOR);
cvtColor(drawImg, grayImg, CV_BGR2GRAY);
//显示下一张图片张数
stringstream NextImg;
int imgNumber = imgNum + 1;
NextImg << imgNumber;
ui.editImgNum->setText(NextImg.str().c_str());
//判断图片是否结束
imgNum++;
if (imgNum==imgNameList.size())
{
ui.btnNextImg->setEnabled(false);
}
imgNum--;
}
六 界面与对话框的退出
6.1 QT整个界面的退出
1)头文件
public slots:
//退出
void on_btnExit_clicked();
2)函数实现
void 类名::on_btnExit_clicked()
{
exit(0);
}
6.2 QT对话框的关闭
1)头文件
public slots:
//停止跟踪编码点
void on_btnStop_clicked();
2)函数实现
void 类名::on_btnStopTracking_clicked()
{
this->close();
}
七 子窗口访问父窗口的成员函数与成员变量
父窗口定义的类:Father;
子窗口定义的类:Son;
void Son::on_pushButton_OutputText_clicked()
{
//通过调用如下这句,子窗口便可以调用父窗口中的成员函数和成员变量了。
Father *p = (Father *) parentWidget(); //关键之处就是这里!
m_SonUi.plainTextEdit_OutputText->appendPlainText( p->GetString());
}
八 删除文件夹内或者文件夹内的所有文件
8.1 头文件
include <QtCore/QCoreApplication>
#include <QDir>
#include <QFileInfoList>
#include <qfileinfo>
#include <QFile>
#include <QDebug>
8.2 函数实现
void Dynamic3DTracking::removefilesindir(const QString& path)
{
QDir dir(path);
QFileInfoList info_list = dir.entryInfoList(QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot | QDir::NoSymLinks | QDir::AllDirs);
foreach(QFileInfo file_info, info_list)
{
if (file_info.isDir())
{
removefilesindir(file_info.absoluteFilePath());
}
else if (file_info.isFile())
{
QFile file(file_info.absoluteFilePath());
qDebug() << "remove file : " << file_info.absoluteFilePath();
file.remove();
}
}
QDir temp_dir;
//temp_dir.rmdir(path) ; //删除文件夹及里面的文件
temp_dir.remove(path); //删除文件夹里面的文件,不包括文件夹本身
qDebug() << "remove empty dir : " << path;
}
8.3 主函数
int main(int argc, char* argv[])
{
QCoreApplication a(argc, argv);
//删除该文件夹下的所有文件
removefilesindir("G:/ProjectFiles/QTProjectFiles/DynamicTrack3D(QT)_new/Dynamic3DTracking/DataFiles/ImageFiles/image/R/");
return a.exec();
}
九 如何在lineEdit中输出int类型的变量
int imgNumBeDealed=20;
stringstream str;
str << imgNumBeDealed;
ui.lineEditImgNum->setText(str.str().c_str());
十 Mat与QImage相互转化的函数
10.1 Mat转化成QImage
QImage DynamicTrackDlg::cvMat2QImage(const cv::Mat& mat)
{
// 8-bits unsigned, NO. OF CHANNELS = 1
if (mat.type() == CV_8UC1)
{
QImage image(mat.cols, mat.rows, QImage::Format_Indexed8);
// Set the color table (used to translate colour indexes to qRgb values)
image.setColorCount(256);
for (int i = 0; i < 256; i++)
{
image.setColor(i, qRgb(i, i, i));
}
// Copy input Mat
uchar *pSrc = mat.data;
for (int row = 0; row < mat.rows; row++)
{
uchar *pDest = image.scanLine(row);
memcpy(pDest, pSrc, mat.cols);
pSrc += mat.step;
}
return image;
}
// 8-bits unsigned, NO. OF CHANNELS = 3
else if (mat.type() == CV_8UC3)
{
// Copy input Mat
const uchar *pSrc = (const uchar*)mat.data;
// Create QImage with same dimensions as input Mat
QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
return image.rgbSwapped();
}
else if (mat.type() == CV_8UC4)
{
qDebug() << "CV_8UC4";
// Copy input Mat
const uchar *pSrc = (const uchar*)mat.data;
// Create QImage with same dimensions as input Mat
QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
return image.copy();
}
else
{
qDebug() << "ERROR: Mat could not be converted to QImage.";
return QImage();
}
}
10.2 QImage转化成Mat的函数
cv::Mat DynamicTrackDlg::QImage2cvMat(QImage image)
{
cv::Mat mat;
qDebug() << image.format();
switch (image.format())
{
case QImage::Format_ARGB32:
case QImage::Format_RGB32:
case QImage::Format_ARGB32_Premultiplied:
mat = cv::Mat(image.height(), image.width(), CV_8UC4, (void*)image.constBits(), image.bytesPerLine());
break;
case QImage::Format_RGB888:
mat = cv::Mat(image.height(), image.width(), CV_8UC3, (void*)image.constBits(), image.bytesPerLine());
cv::cvtColor(mat, mat, CV_BGR2RGB);
break;
case QImage::Format_Indexed8:
mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void*)image.constBits(), image.bytesPerLine());
break;
}
return mat;
}
十一 QGraphicsView类的简单用法
11.1 封装好的.h和.cpp文件
11.2 关于上述的.h和.cpp文件的使用方法:
m_scene = new QGraphicsScene();
m_scene->addItem(&imgItem);
ui.graphicsView->setScene(m_scene);
ui.graphicsView->setDragMode(QGraphicsView::NoDrag);
z = new Graphics_view_zoom(ui.graphicsView);
z->set_modifiers(Qt::NoModifier);
十二 关于QT多线程
由于最近琢磨了好久,利用多线程来控制相机外触发拍摄图片,因而,此处将项目中的多线程知识做个梳理。
QT中自带多线程类,因而我是直接继承使用QT中QThread类的。
12.1 在工程中添加一个类,继承QThread
//开辟两个线程
CamCapThread *threadL,threadR;
threadL = new CamCapThread(LRThread::L);
threadR = new CamCapThread(LRThread::R);
//线程的入口
threadL->start();
threadR->start();
//线程的执行
threadL->run(LRThread::L,vecImgL1,NumRetrieveBuffer);
threadR->run(LRThread::R,vecImgR1,NumRetrieveBuffer);
//关闭线程 需要先后调用这三个函数 quit() wait() delete thread
threadL->quit();
threadR->quit();
threadL->wait();
threadR->wait();
delete threadL;
delete threadR;
十三 从主窗口启动子窗口
主窗口的类:QuickCalculate
子窗口的类:imgshowDlg
void QuickCalculate::on_btn_ShowImg_clicked()
{
imgshowDlg imgshowDlgModel(this);
imgshowDlgModel.exec();
}
十四 QMessageBox消息窗口的调用
以下提供几段代码来说明QMessageBox的常见用法:
头文件:include”QMessageBox”
QMessageBox::critical(this,GBK::ToUnicode("坏消息"),GBK::ToUnicode("左相机关闭失败,请检查"),
QMessageBox::Ok|QMessageBox::Cancel,QMessageBox::Ok);
QMessageBox::information(NULL, GBK::ToUnicode("友情提示"), GBK::ToUnicode("图片已经拍摄完成"));
QMessageBox::critical(this,GBK::ToUnicode("坏消息"),GBK::ToUnicode("左相机连接失败,请检查"));
十五 vs2015+QT5添加多个子对话框
在主对话框中Form Files上右键->添加->(最下面)Add Qt Class->Qt GUI Class->修改类名,则能生成对应ui文件、.h文件及.cpp文件啦。注意:此处的基类选择:QDialog
注意:Form Files上右键之前,点击Form Files,QT插件中,点击“convert project to qmake generated project”
十六 QT中如何显示调试界面
打开QT工程——>项目属性:
在命令行输入:
editbin /SUBSYSTEM:CONSOLE "$(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName).exe"
十七 QT如何处理密集型耗时的事情(频繁调用QApplication::processEvents)
有时候需要处理一些跟界面无关的但非常耗时的事情,这些事情跟界面在同一个线程中,由于时间太长,导致界面无法响应,处于“假死”状态。例如:在应用程序中保存文件到硬盘上,从开始保存直到文件保存完毕,程序不响应用户的任何操作,窗口也不会重新绘制,从而处于“无法响应”状态,这是一个非常糟糕的体验 。
在这种情况下,有一种方法是使用多线程,即在子线程中处理文件保存,主线程负责界面相关。
而如果不想使用多线程,最简单的办法就是在文件保存过程中频繁调用QApplication::processEvents()。该函数的作用是让程序处理那些还没有处理的事件,然后再把使用权返回给调用者。
bool MyApp::writeFile(const QString &filename)
{
QFile file(filename);
...
QApplication::setOverrideCursor(Qt::WaitCursor);
for(int r = 0; r != rowCount; ++r)
{
for(int c = 0; c != colCount; ++c)
{
out << table(r,c);
qApp.processEvents();
}
}
QApplication::restoreOverrideCursor();
}
这样一来,程序就能响应了。
但是,该方法有一个问题:可能正在保存文件的过程中,用户不小心又单击了保存,或不小心关闭了程序主窗口,这样会产生意想不到的后果。
解决这个问题的最简单的办法是替换成:
qApp->processEvents(QEventLoop::ExcludeUserInputEvents);//它可以忽略用户的输入(鼠标和键盘事件)。