-
-
一 QT定时器
-
1.1 QObject类的定时器:
- 1.1.1 使用的示例代码:
- 1.2 QTimer类的定时器
-
1.1 QObject类的定时器:
-
二 QT界面布局
- 2.1 如何将布局上下按比例设置大小?
-
三 QT5+VS2013程序发布
- 3.1 骤如下:
-
四 int与QString相互转化
- 4.1 int转化为QString
- 4.2 将QString转化为Int
-
五 设置打开文件路径+读取该目录下的所有图片
- 5.1 设置打开文件路径的程序中无中文时
-
5.2 设置打开文件路径的程序中有中文时
- 5.2.1 前提:
- 5.2.2 代码示例:
-
5.3 读取该路径下的图片
- 5.3.1 在5.2的基础上
- 5.3.2 读取下一张图片的按钮
-
六 界面与对话框的退出
- 6.1 QT整个界面的退出
- 6.2 QT对话框的关闭
- 七 子窗口访问父窗口的成员函数与成员变量
-
八 删除文件夹内或者文件夹内的所有文件
- 8.1 头文件
- 8.2 函数实现
- 8.3 主函数
- 九 如何在lineEdit中输出int类型的变量
-
十 Mat与QImage相互转化的函数
- 10.1 Mat转化成QImage
- 10.2 QImage转化成Mat的函数
-
十一 QGraphicsView类的简单用法
- 11.1 封装好的.h和.cpp文件
- 11.2 关于上述的.h和.cpp文件的使用方法:
-
十二 关于QT多线程
- 12.1 在工程中添加一个类,继承QThread
- 十三 从主窗口启动子窗口
- 十四 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;
方法:先点全选,右侧的布局“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文件夹拷贝给其他人的电脑就可用了。
//头文件 #include #include //函数实现 int imgNumber=50; stringstream NextImg; NextImg << imgNumber; ui.editImgNum->setText(NextImg.str().c_str()); // void setText(const QString &);4.2 将QString转化为Int
//头文件 #include //函数实现 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
-
做好的界面如下:
//头文件中 #include #include 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 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 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#include #include #include #include #include8.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);//它可以忽略用户的输入(鼠标和键盘事件)。