Qt常遇问题小集合

QThread之quit() 和 terminate()

  • quit() 通知线程的事件循环退出...如果线程没有事件循环,就啥都不做。
  • terminate() 可以简单理解为强制退出

示例:

class MyThread:public QThread
{
    Q_OBJECT
protected:
    void run()
    {
        //处理1

        //处理2

        int ret = exec(); //线程事件循环
        qDebug() << "return code:" << ret;
    }
};

假设1 线程正在执行 处理1 的位置

    如果调用quit(),线程会一直走到最后,然后线程退出。

    如果调用terminate(),线程可能会执行完处理1直接退出,也可能没执行完处理1直接退出。

    如果不调用quit和terminate,线程执行完处理1和处理2,进入事件循环不会退出。

假设2 线程执行到exec()的位置

    如果调用quit(),线程会一直走到最后,然后线程退出。

    如果调用terminate(),线程直接退出,而且不会打印最后一行

    如果不调用quit和terminate,处于事件循环不会退出。

假设3 注释调exec()

    quit()不会起到任何作用,且线程执行完处理1和处理2直接退出。

特别注意:通常情况下我们以继承的方式创建线程都忽略不写exec(),所以会误认为quit()没有作用!!!

 

QMetaObject::invokeMethod

官方文档举例一:
QMetaObject::invokeMethod(thread, "quit", Qt::QueuedConnection);

官方文档举例二:

QString retVal;​
​​QMetaObject::invokeMethod(obj, "compute", Qt::DirectConnection,
                            Q_RETURN_ARG(QString, retVal),
                            Q_ARG(QString, "sqrt"),
                            Q_ARG(int, 42),
                            Q_ARG(double, 9.7));

从上面的例子,我们只能看到invokeMethod的调用方式和起到异步调用的效果。那什么情况我们用这种方式呢?比如线程更改UI的时候会很方便。

 void run()
 {
        //...            
       QMetaObject::invokeMethod(parent(),"updateUI",Qt::QueuedConnection,Q_ARG(QString,"修改"));

        exec();
 }

假设主程序中有个槽函数updateUI(QString)用来更新UI上的显示,通过上述调用的时候updateUI函数的执行会自动在主进程的状态执行,避免的线程操作UI的隐患。这样写的好处就是减少了信号槽的定义关联的麻烦。

 

快速打包Qt程序

比如说完成了一个Qt程序 'xxx.exe',需要把它打包发布,一个一个找依赖耗时耗力还没有保证。这时我们就需要借助Qt5.11.1\5.11.1\msvc2017_64\bin\windeployqt.exe,它能自动把程序依赖拷贝到当前的目录里去,就像这样

windeployqt xxx.exe

 

十六进制字符转十进制的方法

    QByteArray array;
    array.resize(2);
    array[0] = 0x07;
    array[1] = 0xE3;
    qDebug() << array.toHex().data(); //07e3
    bool ok;
    qDebug() << array.toHex().toInt(&ok,16); //2019

 

一句话理解下installEventFilter

ui.pushbutton->installEventFilter(this);

把ui.pushbutton的消息事件放在当前这个类this来处理

 

Qt父窗口与子窗口摩擦的一些小毛病

一、通过继承QWidget用来作为子类使用,发现setStyleSheet不管事了~~~写以下几行解决

void FirstChild::paintEvent(QPaintEvent *e)
{
    QPainter painter(this);
 
    QStyleOption o;
    o.initFrom(this);
    style()->drawPrimitive(QStyle::PE_Widget,&o,&painter,this);
}

二、鼠标点击到子窗口上,希望无视子窗口,直接由父窗口来处理鼠标事件~~~加一句属性即可

setAttribute(Qt::WA_TransparentForMouseEvents);

三、父窗口中存在多个子窗口,希望某个子窗口显示在最前面或最后面~~~这些函数会帮到你

void QWidget::stackUnder(QWidget *w) 
//放在w后面,注意两个子窗口要是同级的 
//例如:a.stackUnder(b),b在前显示
 
[slot] void QWidget::raise() 
//提到最前显示
 
[slot] void QWidget::lower() 
//提到最后显示

 

QTreeWidget下查询节点

//递归查找
QTreeWidgetItem *Dialog::findChildItemRecursion(QTreeWidgetItem *parent, QString name)
{
    if(parent->text(0) == name)
        return parent;
 
    int nCount = parent->childCount();
    for(int i=0;i<nCount;i++)
    {
        QTreeWidgetItem* childItem = findChildItemRecursion(parent->child(i),name);
        if(childItem != NULL)
        {
            return childItem;
        }
    }
 
    return NULL;
}
 
//遍历查找
QTreeWidgetItem *Dialog::findChildItemTraverse(QTreeWidgetItem *parent, QString name)
{
    QTreeWidgetItemIterator iter(parent);
    while(*iter)
    {
        if((*iter)->text(0) == name)
        {
            return (*iter);
        }
        ++iter;
    }
    return NULL;
}

 

Qt设置窗口透明

一、设置Flags和Attribute的方式,子控件不受影响
setWindowFlags(Qt::FramelessWindowHint);//windows下要加
setAttribute(Qt::WA_TranslucentBackground,true);
二、通过设置窗口透明度,子控件也受影响

setWindowOpacity(0.0);

三、设置子控件透明

QGraphicsOpacityEffect* effect = new QGraphicsOpacityEffect(this);
effect->setOpacity(0.5);
ui->pushButton->setGraphicsEffect(effect);

 

Qt样式表引用图片---路径问题

相对路径写法一
this->setStyleSheet("border-image:url(image/pic.jpg)");    
相对路径写法二
this->setStyleSheet("border-image:url(./image/pic.jpg)");   
从Qrc中加载
 this->setStyleSheet("border-image:url(:/image/pic.jpg)");

 

 Qt打日志

先来认识下这几个弟兄

int func( char* prev_param, ...);
三个点可以理解为接收多个参数用的

 typedef char *  va_list;
由于多个参数都是按顺序存放在堆栈中,这个变量可以理解为指向第一个参数


void va_start(   va_list va_list, prev_param  );
可以认为是给va_list赋值

void va_end(   va_list va_list);
最后还免不了要释放

使用重载分别实现了两种传参的方法,上代码:
 

#include <QThread>
#include <QTime>
#include <QFile>
#include <QDir>
#include <windows.h>
 
void writeLog(QString msg)
{
    //系统当前时间
    QString strTime = QTime::currentTime().toString("hh:mm:ss.zzz");
    //进程ID
    DWORD lpId = GetCurrentProcessId();
 
    //创建目录
    QString strDir("c:/log/");
    QDir dir(strDir);
    if(!dir.exists())
        dir.mkdir(strDir);
 
    //写日志
    QFile file("c:/log/logs.log");
    if(file.open(QIODevice::WriteOnly | QIODevice::Append))
    {
       QTextStream stream(&file);
       stream << QString("%1---PID:[%2]---: %3\r\n").arg(strTime).arg(lpId).arg(msg);
       file.close();
    }
}
 
void writeLog(char* pMsg,...)
{
    va_list argList;
    va_start(argList,pMsg);
 
    QString strResult = QString::vasprintf(pMsg,argList);
 
    va_end(argList);
 
    writeLog(strResult);
}

//调用
    writeLog(const_cast<char*>("%s %s"),"hello","Qt");     //void writeLog(char* pMsg,...)
    writeLog(QString("%1 %2").arg("hello").arg("C++"));     //void writeLog(QString msg)   

 

 

(未完待续...)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章