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)   

 

 

(未完待續...)

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