参考链接:
璎珞qc:Qt之QImage类.
沙振宇:Qt输出打印信息的日志到文件(两种方式).
tandesir:Qt测算程序运行时间.
半生瓜のblog 【QT】QT容器
百科不全书之QT常用函数
1. QT定时器的使用
// 头文件
#include <QTimer>
// 使用方法
QTimer *time_my_ = new QTimer(this);
connect(time_my_,SIGNAL(timeout()),this,SLOT(TsetTimeOut())); //定时时间到执行的任务;
time_my_->start(500); // 传入的整数单位是毫秒
connect(time_my_,SIGNAL(timeout()),this,SLOT(TsetTimeOut)); //win 下需加()
// 函数的声明
public slots:
void TsetTimeOut();
2 QT常用数据转化
//字符转数字
int QString::toInt(bool *ok = Q_NULLPTR, int base = 10) const
float QString::toFloat(bool *ok = Q_NULLPTR) const
double QString::toDouble(bool *ok = Q_NULLPTR) const
QString str("20210315");
int num = str.toInt();
// 数字转字符
QString number(int n, int base = 10)
QString number(int n, char format = 'g', int precision = 6)
// 时间转QString
public QDateTime qdate = QDateTime.currentDateTime();
datetime = qdate.toString("yyyy年MM月dd日ddddhh:mm:ss");
//string转QString
std::string s;
QString str=QString::fromStdString(s);
//QString转string
std::string s;
QString str;
s = str.toStdString();
3 QT的QPainterPath
QPainterPath 类(绘图路径)提供了一个容器,用于绘图操作,可以创建和重用图形形状。
void QPainterPath::addEllipse(const QRectF & boundingRectangle) // 椭圆
void QPainterPath::addPolygon(const QPolygonF & polygon) // 多边形
void QPainterPath::addRect(const QRectF & rectangle) // 矩形
void QPainterPath::addText(const QPointF & point, const QFont & font, const QString & text) // 文本
void QPainterPath::arcTo(const QRectF & rectangle, qreal startAngle, qreal sweepLength) // 弧形
void QPainterPath::cubicTo(const QPointF & c1, const QPointF & c2, const QPointF & endPoint) // 贝塞尔曲线
4 QT使用线程
参考连接 link
Qt有两种多线程的方法,其中一种是继承QThread的run函数,另外一种是把一个继承于QObject的类转移到一个Thread里。就是通过QObject来实现,和线程的交互通过信号和槽(实际上其实是通过事件)联系。 Qt4.8之前都是使用继承QThread的run这种方法,但是Qt4.8之后,Qt官方建议使用第二种方法。
QObject是Qt框架的基本类,但凡涉及到信号槽有关的类都是继承于QObject。QObject是一个功能异常强大的类,它提供了Qt关键技术信号和槽的支持以及事件系统的支持,同时它提供了线程操作的接口,也就是QObject是可以选择不同的线程里执行的。
QObject的线程转移函数是:void moveToThread(QThread * targetThread) ,通过此函数可以把一个**顶层Object(就是没有父级)**转移到一个新的线程里。
用QObject来实现多线程有个非常好的优点,就是默认就支持事件循环(Qt的许多非GUI类也需要事件循环支持,如QTimer、QTcpSocket),QThread要支持事件循环需要在QThread::run()中调用QThread::exec()来提供对消息循环的支持,否则那些需要事件循环支持的类都不能正常发送信号,因此如果要使用信号和槽,那就直接使用QObject来实现多线程。
使用QObject创建多线程的方法如下:
1.写一个继承QObject的类,对需要进行复杂耗时逻辑的入口函数声明为槽函数
2.此类在旧线程new出来,不能给它设置任何父对象
3.同时声明一个QThread对象,在官方例子里,QThread并没有new出来,这样在析构时就需要调用QThread::wait(),如果是堆分配的话, 可以通过deleteLater来让线程自杀
4.把obj通过moveToThread方法转移到新线程中,此时object已经是在线程中了
5.把线程的finished信号和object的deleteLater槽连接,这个信号槽必须连接,否则会内存泄漏
6.正常连接其他信号和槽(在连接信号槽之前调用moveToThread,不需要处理connect的第五个参数,否则就显示声明用Qt::QueuedConnection来连接)
7.初始化完后调用’QThread::start()'来启动线程
8.在逻辑结束后,调用QThread::quit退出线程的事件循环
// QT官方文档
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork(const QString ¶meter) {
QString result;
/* ... here is the expensive or blocking operation ... */
emit resultReady(result);
}
signals:
void resultReady(const QString &result);
};
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
Controller() {
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
connect(this, &Controller::operate, worker, &Worker::doWork);
connect(worker, &Worker::resultReady, this, &Controller::handleResults);
workerThread.start();
}
~Controller() {
workerThread.quit();
workerThread.wait();
}
public slots:
void handleResults(const QString &);
signals:
void operate(const QString &);
5 QT常用宏
__LINE__//显示所在行号
__func__//显示所在函数
__TIME__//显示当前时间
__DATE__//显示当前日期
__FILE__//显示所处文件名,在源代码中插入当前源代码文件名
__STDC__//编译器遵循ANSI C标准时该标识被赋值为1;
6 QT打印日志
注册qInstallMessageHandler
#include <fstream> // std::ofstream
std::ofstream g_OutputDebug;
static bool flag=false;
void outputMessage(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
// 加锁
static QMutex mutex;
mutex.lock();
QString text;
switch(type) {
case QtDebugMsg:
text = QString("Debug: ");
break;
case QtWarningMsg:
text = QString("Warning: ");
break;
case QtCriticalMsg:
text = QString("Critical:");
break;
case QtFatalMsg:
text = QString("Fatal: ");
break;
default:
text = QString("Debug: ");
}
QString context_info = QString("F:(%1) L:(%2)").arg(QString(context.file)).arg(context.line); // F文件信息L行数
// QString current_date_time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
// QString current_date = QString("(%1)").arg(current_date_time); std::string message = qPrintable(QString("%1 %2 \t%3 \t%4").arg(text).arg(context_info).arg(current_date).arg(msg));
std::string message = qPrintable(QString("%1 %2 \t%3 ").arg(text).arg(context_info).arg(msg));
g_OutputDebug << message << "\r\n"; // std::ofstream
// 解锁
mutex.unlock();
}
在mian函数中注册
qInstallMessageHandler(outputMessage);
g_OutputDebug.open(qPrintable(QString(QString(QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss").append("-log.txt")))), std::ios::out | std::ios::trunc);
std::cout
#include "fstream"
std::ofstream g_log(QString(QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss").append("-logstr.log")).toStdString());
std::cout.rdbuf(g_log.rdbuf());
7 QT打印程序耗时
gettimeofday(),精度us级
#include <QDebug>
#include <sys/time.h>
struct timeval tpstart,tpend;
float timeuse;
gettimeofday(&tpstart,NULL);
function();
gettimeofday(&tpend,NULL);
timeuse=(1000000*(tpend.tv_sec-tpstart.tv_sec) + tpend.tv_usec-tpstart.tv_usec)/1000000.0;
qDebug()<<timeuse<<"s";
clock(),精度为ms级
#include <QDebug>
#include <sys/time.h>
double time_Start = (double)clock();
function();
double time_End = (double)clock();
qDebug()<<(time_End - time_Start)/1000.0<<"s";
QTime,精度ms级用
#include <QDebug>
#include <QTime>
QTime time;
time.start();
function();
qDebug()<<time.elapsed()/1000.0<<"s";
8 QT的conf文件
项目 | Value |
---|---|
Prefix | QCoreApplication::applicationDirPath() 绝对路径 |
Documentation | doc |
Headers | include |
Libraries | lib |
Binaries | bin |
Plugins | plugins |
Data | . |
Translations | translations |
Settings | . |
Examples | . |
Demos | . |
[Paths]
Prefix=D:/Qt/4.8.5 #安装路径 注意不要使用反斜杠
Libraries=./lib
Binaries=./bin
Plugins=./plugins
Imports=./imports
Qml2Imports=./qml
Translations = ./translations
Documentation = ./doc
Headers = ./include
Demos= /.demos
Examples= ./examples
Data = .
Settings = .
9 QT的image类
在Qt中有两种表示图像的类,Qt:QImage和QPixmap,还有QBitmap来存储单色的图像,比如遮罩。通过使用类中的方法可以实现图像的基本操作(缩放、旋转等等。
参考QT的帮助文档,可以显示的图像类型有BMP、GIF、JPG、JPEG、PNG、TIFF、PBM、PGM、PPM、XBM、XPM。
QImage和QPixmap的区别:QImage为图像的像素级访问做了优化,QPixmap使用底层平台的绘制系统进行绘制,无法提供像素级别的操作,而QImage则是使用独立于硬件的绘制系统。
QImage(uchar * data, int width, int height, Format format) // 浅拷贝
QImage(const uchar * data, int width, int height, Format format) // 浅拷贝
QImage(uchar * data, int width, int height, int bytesPerLine, Format format) // 浅拷贝
QImage(const uchar * data, int width, int height, int bytesPerLine, Format format) // 浅拷贝
QImage QImage::copy(const QRect & rectangle = QRect()) const // 深拷贝
QImage QImage::rgbSwapped() const // 浅拷贝
从构造函数可以得知只要知道:uchar * data 指向图像数据的uchar*型地址 int width图像宽度 int height图像高度 int bytesPerLine图像格式或者是图像的每行字节数=通道*宽度
那么就可以构造出一个QImage的实体,而这里讨论的是,这个实体是与传入构造函数的图像数据地址指向的内存块是同一块内存,即浅拷贝
const uchar *QImage::bits() const //获取图像的首地址
int QImage::byteCount() const // 获取图像的总字节数
int QImage::bytesPerLine() const // 获取图像每行字节数
// 用来实现图像的缩放
//Qt::AspectRatioMode可以选择的模式有:IgnoreAspectRatio(忽略长宽比),KeepAspectRatio(保持长宽比),KeepAspectRatioByExpanding(通过扩展保持纵横比)
//Qt::TransformationMode 可以选择的有:FastTransformation(快速转型),SmoothTransformation(平滑变换)
//scaled函数中width和height表示缩放后图像的宽和高,即将原图像缩放到(width,height)大小。
QImage scaled(const QSize &s, Qt::AspectRatioMode aspectMode = Qt::IgnoreAspectRatio, Qt::TransformationMode mode = Qt::FastTransformation) const;
// 将图片的红色和蓝色交换,将RGB转为BGR图像
QImage rgbSwapped() const &
QImage btest_bgr=rgb_test.rgbSwappen();
// 将彩色图转换为灰度图
QImage::convertToFormat
QImage image(fileName);
QImage gray = image.convertToFormat(QImage::Format_Grayscale8);
//图像保存
bool save(const QString &fileName, const char *format = Q_NULLPTR, int quality = -1) const;
//quality必须在0到100或-1范围内。指定0来获得小的压缩文件,100用于大的未压缩文件,和-1(默认)使用默认设置。rormat是选择保存的格式,支持格式如下:
//BMP(Windows Bitmap);GIF(Graphic Interchange Format (optional);JPG(Joint Photographic Experts Group);JPEG(Joint Photographic Experts Group);PNG(Portable Network Graphics);PBM(Portable Bitmap);PGM(Portable Graymap);PPM(Portable Pixmap);XBM(X11 Bitmap);XPM(X11 Pixmap);
QString imagePath = “image.bmp”;
QImage image;
image.save(imagePath,"BMP");
10 QT的各种路径信息
bool QDir::setCurrent("/home/csy");//设置应用程序当前目录
QString QDir::currentPath();//当前工作目录
QString QCoreApplication::applicationDirPath();//运行程序用户目录路径
QString QDir::homePath() =QString QStandardPaths::writableLocation(QStandardPaths::HomeLocation); //结果为 "/home/csy"
QStringList QStandardPaths::standardLocations(QStandardPaths::HomeLocation);//结果为("/home/csy")
QString QStandardPaths::displayName(QStandardPaths::HomeLocation) // 结果为 "Home" 感觉不是很好用
// 数据存放位置
QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)QStandardPaths::standardLocations(QStandardPaths::AppConfigLocation);
QString QStandardPaths::locate(StandardLocation type, const QString &fileName, LocateOptions options = LocateFile) //查找名为fileName的文件或目录 返回目录
QString str2=QCoreApplication::applicationDirPath()+"/"+"video";
char* ch;
QByteArray ba = str2.toLatin1();
ch=ba.data();
qDebug()<<__LINE__<<__FILE__<<ch;
if(NULL==opendir(ch)){
qDebug()<<__LINE__<<__FILE__<<"打开文件夹为空";
int ret=mkdir(ch,0775);
if(ret == -1){
perror("mkdir fail:");
}
}
QDir::setCurrent(QCoreApplication::applicationDirPath());
QString str2=(QCoreApplication::applicationDirPath()+"/"+"log/");
char* ch;
QByteArray ba = str2.toLatin1();
ch=ba.data();
qDebug()<<__LINE__<<__FILE__<<ch;
if(NULL==opendir(ch)){
qDebug()<<__LINE__<<__FILE__<<"打开文件夹为空";
int ret=mkdir(ch,0775);
if(ret == -1){
perror("mkdir fail:");
}
}else
{
qDebug()<<__LINE__<<__FILE__<<"文件夹已经存在";
}
g_OutputDebug.open(qPrintable(QString(QString(str2+QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss")+"-log.txt")))
,std::ios::out | std::ios::trunc);
//xprop WM_CLASS
11 QT执行系统命令
// 方法1
// 调用Linux C函数库中的system(const char *string);
system("ls");
system("gnome-terminal -- bash -c 'sudo ls;exec bash' ");
// 方法2
QProcess ::execute("ls");
// 方法3
QProcess *proc = new QProcess;
proc->start("ls");
// 1 2 会阻塞进程; 3 不会阻塞
// 当命令中存在管道(|)和重定向(>)时,只能使用第1种,第2种和第3种属于Qt自身的,不能识别这两种符号。
12 QT多个信号连接到一个槽
my_paint[i]->setObjectName((QString::number(i,10))); // 先设置name
// 在槽函数中判断
QObject *object = QObject::sender();
my_paintwidget *push_button = qobject_cast<my_paintwidget *>(object);
QString object_name = push_button->objectName();
// 一步到位型
QString object_name = qobject_cast<my_paintwidget *>(QObject::sender())->objectName();
13 QT的中文字符
在MinGW模式下 中文字符的判断和输入无任何问题
在MSVC模式下 会出现 error: C2001: 常量中有换行符等问题
解决方法
14 QT的QString函数
//判断字符串str中是否有子字符串。如果有则返回true,如果没有则返回false
contains((const QString &s, Qt::CaseSensitivity cs)
//用于在给定的索引位置插入字符串str
insert(i, QString::fromUtf8(s))
// 用字符串替换从索引位置开始的n个字符。
replace(int position, int n, const QString & after)
// 用于在一个字符串中查找另一个字符串,返回第一次出现的索引位置,如果没有找到,返回-1。
indexOf(const QStringRef &s, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive)
if(str.contains(u8"二"))
n=str.indexOf("二");
str.replace(n,1,"二");
QString str2="abcdefg";
QString str3="abcdefg";
str2.replace(2,1,"11"); // str2 "ab11defg"
str3.replace(2,3,"11"); // str3 "ab11fg"
15 QT的QStringList
QStringList pList = pout.split(","); // 以 , 分割字符串
QString str=pList.join(","); // 以 , 连接字符串
QStringList weekList;
weekList<<"星期一"<<"星期二"<<"星期三"<<"星期四"<<"星期五"<<"星期六";
weekList.append("星期天");//尾插
qDebug()<<weekList;
//for遍历链表
for(int i = 0 ;i < weekList.size();i++)
{
qDebug()<<weekList.at(i);
}
//foreach遍历链表
foreach (QString ss, weekList) {
qDebug()<<ss;
}
//STL风格迭代器
QStringList::iterator it = weekList.begin();
for(;it != weekList.end();it++)
{
qDebug()<<*it;
}
//JAVA风格迭代
QListIterator<QString>itr(weekList);
while (itr.hasNext()) {
qDebug()<<itr.next();//java风格的迭代器初识位置在第一个元素的前一个位置
}
//查看链表中是否包含某个元素
qDebug()<<weekList.contains("星期八");
//插入元素
weekList.insert(0,"星期零");
weekList.append("星期八");
//删除元素
weekList.removeFirst();
weekList.removeLast();
weekList.removeOne("星期一");
weekList.removeAt(0);
weekList.clear();
16 QT的STL数据类型
顺序容器:
QList、QLinkedList、QVector、QStack和QQueue。
对于大多数应用程序,QList是最好的类型。虽然它是作为数组列表实现的,但是它提供了非常快的前置和附加。
如果你真的需要一个链表,使用QLinkedList;
如果您希望您的项目占用连续的内存位置,请使用QVector。
QStack和QQueue是提供LIFO和FIFO语义的便利类
关联容器
QMap、QMultiMap、QHash、QMultiHash和QSet。QMultiMap容器方便地支持与单个键相关联的多个值。QHash容器通过使用哈希函数而不是对排序集进行二进制搜索,从而提供更快的查找。
QLIST
QList< T >是最常用的容器类。继承自QList类的子类有QItemSelection、QQueue、QStringList、QTestEventList.
可用运算符<< 、append()、prepend()进行添加元素,insert()进行插入。QList< T >维护了一个指针数组,数组元素指向每一个链表项,因此QList< T > 提供了基于下标的快速访问。
QList<int>list;
list<<1<<2<<3<<4<<5; //添加与元素
list.append(0);
list.prepend(6);
list.insert(0,99);
list.at(2); //查找元素
list[2];
list.replace(1,66); //修改元素
list[2] = 77;
list.removeFirst(); //删除元素
list.removeLast();
list.contains(8); //查看是否包含
list.removeAt(2);//删除指定位置元素
list.removeOne(66); //指定元素删除
list.clear(); //清空链表
QList<int>numList;
numList<<10<<11<<12<<13;
//读写迭代器
QList<int>::iterator it_numRW;
for( it_numRW = numList.begin();it_numRW != numList.end();it_numRW++)
{
*it_numRW =*it_numRW * 10;
qDebug()<<*it_numRW;
}
qDebug()<<"---";
//只读迭代器
QList<int>::const_iterator it_numR;
//constEnd方法返回的迭代器指向最后一个元素之后,是虚拟的。
for( it_numR = numList.constBegin();it_numR != numList.constEnd();it_numR++)
{
qDebug()<<*it_numR;
}
qDebug()<<"---";
QVector
QVector在相邻的内存中存储给定数据类型T的一组数据。在QVector前部或中间位置插入操作速度都很慢,因为会导致内存中大量数据的移动。访问数据可使用下标,也可以使用迭代器。继承自QVector类的子类有QPolygon、QPolygonF、QStack。
QVector<QString>vStarts;
//添加元素
vStarts<<"星期1"<<"星期2"<<"星期3";
vStarts.append("星期4");
vStarts.prepend("星期5");
vStarts.insert(0,"星期6");
//修改元素
vStarts.replace(0,"星期六");
//删除元素
vStarts.remove(0);
vStarts.removeFirst();
vStarts.removeAll("星期日");
//访问元素
vStarts[2];
vStarts.at(2);
vStarts.contains("星期日");
//JAVA风格只读迭代
QVectorIterator<QString>it_sr(vStarts);
for(it_sr.toFront();it_sr.hasNext();)
{
qDebug()<<it_sr.next();
}
//JAVA风格读写迭代
QMutableVectorIterator<QString>it_srw(vStarts);
for(it_srw.toFront();it_srw.hasNext();)
{
QString s = it_srw.next();
if(!QString::compare(s,"星期1"))
{
it_srw.setValue("星期一");
}
}
qDebug()<<vStarts;
QMap
QMap与QHash差别:
QHash比QMap查找速度更快。
QHash以任意顺序存储,QMap以key顺序存储数据。
QHash的key必须提供operator==()及一个全局的qHash(key)函数,而QMap必须提供operator<()函数。
可以直接使用[]来插入一个键值对或者键的值
QMap默认是一个键对应一个值,也可以用insertMulti()进行一键多值的插入,对于此种情况,使用QMap的子类QMutiMap更方便
QMap<QString,int>map;//QMap是按照键来有序存放的
map["one"]=1;
map["two"]=2;
map["three"]=3;
map.insert("seven",7);
//获取键值的时候,使用“[]”操作符时,如果map中没有该键,会自动插入该键值对
int value=map["six"];
qDebug()<<value;
qDebug()<<map.contains("six");
qDebug()<<map.value("one");
QMap<QString,int>::const_iterator it;
for(it=map.constBegin();it!=map.constEnd();++it)
{
qDebug()<<*it;
}
----------------------------------------
QMap<QString,int>::const_iterator it=map.begin();
while(it!=map.end())
{
std::cout<<*it;
++it;
}
17 QT播放WAV
// 1 qt发出普通的声音
void QApplication::beep();
// 2 qt播放wav 声音
#include <QSound>
QSound *sound;
sound=new QSound("22.wav");
sound->play();
sound->isFinished()); // 判断是否播放完成 返回BOOL值
sound->stop(); // 停止播放
sound->setLoops(int number)// 设置播放音频的循环次数
sound->loopsRemaining()// 该函数返回int型 剩余循环次数
1111 QT常用数据转化
// A code block
var foo = 'bar';
111 QT常用数据转化
// A code block
var foo = 'bar';
111 QT常用数据转化
// A code block
var foo = 'bar';