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)
(未完待續...)