【轉】Qt開發經驗C++ 飛揚青雲


原文地址:https://gitee.com/feiyangqingyun/qtkaifajingyan

一、開發經驗總結

  1. 當編譯發現大量錯誤的時候,從第一個看起,一個一個的解決,不要急着去看下一個錯誤,往往后面的錯誤都是由於前面的錯誤引起的,第一個解決后很可能都解決了。

  2. 定時器是個好東西,學會好使用它,有時候用QTimer::singleShot可以解決意想不到的問題。

  3. 打開creator,在構建套件的環境中增加MAKEFLAGS=-j8,可以不用每次設置多線程編譯。珍愛時間和生命。新版的QtCreator已經默認就是j8。

  4. 如果你想順利用QtCreator部署安卓程序,首先你要在AndroidStudio 里面配置成功,把坑全部趟平。

  5. 很多時候找到Qt對應封裝的方法后,記得多看看該函數的重載,多個參數的,你會發現不一樣的世界,有時候會恍然大悟,原來Qt已經幫我們封裝好了。

  6. 可以在pro文件中寫上標記版本號+ico圖標(Qt5才支持)

VERSION     = 2018.7.25
RC_ICONS    = main0.ico
  1. 管理員運行程序,限定在MSVC編譯器。
QMAKE_LFLAGS += /MANIFESTUAC:"level='requireAdministrator' uiAccess='false'" #以管理員運行
QMAKE_LFLAGS += /SUBSYSTEM:WINDOWS,"5.01" #VS2013 在XP運行
  1. 運行文件附帶調試輸出窗口
    CONFIG += console pro

  2. 繪制平鋪背景QPainter::drawTiledPixmap,繪制圓角矩形QPainter::drawRoundedRect(),而不是QPainter::drawRoundRect();

  3. 移除舊的樣式

//移除原有樣式
style()->unpolish(ui->btn);
//重新設置新的該控件的樣式。
style()->polish(ui->btn);
  1. 獲取類的屬性
const QMetaObject *metaobject = object->metaObject();
int count = metaobject->propertyCount();
for (int i = 0; i < count; ++i) {
    QMetaProperty metaproperty = metaobject->property(i);
    const char *name = metaproperty.name();
    QVariant value = object->property(name);
    qDebug() << name << value;
}
  1. Qt內置圖標封裝在QStyle中,大概七十多個圖標,可以直接拿來用。
    QStyle::SP_TitleBarMenuButton

  2. 根據操作系統位數判斷加載

win32 {
    contains(DEFINES, WIN64) { DESTDIR = $${PWD}/../../bin64
    } else { DESTDIR = $${PWD}/../../bin32 }
}
  1. Qt5增強了很多安全性驗證,如果出現setGeometry: Unable to set geometry,請將該控件的可見移到加入布局之后。

  2. 可以將控件A添加到布局,然后控件B設置該布局,這種靈活性大大提高了控件的組合度,比如可以在文本框左側右側增加一個搜索按鈕,按鈕設置圖標即可。

QPushButton *btn = new QPushButton;
btn->resize(30, ui->lineEdit->height());
QHBoxLayout *layout = new QHBoxLayout(ui->lineEdit);
layout->setMargin(0);
layout->addStretch();
layout->addWidget(btn);
  1. 對QLCDNumber控件設置樣式,需要將QLCDNumber的segmentstyle設置為flat。

  2. 巧妙的使用findChildren可以查找該控件下的所有子控件。findChild為查找單個。

//查找指定類名objectName的控件
QList<QWidget *> widgets = parentWidget.findChildren<QWidget *>("widgetname");
//查找所有QPushButton
QList<QPushButton *> allPButtons = parentWidget.findChildren<QPushButton *>();
//查找一級子控件,不然會一直遍歷所有子控件
QList<QPushButton *> childButtons = parentWidget.findChildren<QPushButton *>(QString(), Qt::FindDirectChildrenOnly);
  1. 巧妙的使用inherits判斷是否屬於某種類。
QTimer *timer = new QTimer;         // QTimer inherits QObject
timer->inherits("QTimer");          // returns true
timer->inherits("QObject");         // returns true
timer->inherits("QAbstractButton"); // returns false
  1. 使用弱屬性機制,可以存儲臨時的值用於傳遞判斷。可以通過widget->dynamicPropertyNames()列出所有弱屬性名稱,然后通過widget->property("name")取出對應的弱屬性的值。

  2. 在開發時, 無論是出於維護的便捷性, 還是節省內存資源的考慮, 都應該有一個 qss 文件來存放所有的樣式表, 而不應該將 setStyleSheet 寫的到處都是。如果是初學階段或者測試階段可以直接UI上右鍵設置樣式表,正式項目還是建議統一到一個qss樣式表文件比較好,統一管理。

  3. 如果出現Z-order assignment: is not a valid widget.錯誤提示,用記事本打開對應的ui文件,找到 為空的地方,刪除即可。

  4. 善於利用QComboBox的addItem的第二個參數設置用戶數據,可以實現很多效果,使用itemData取出來。

  5. 如果用了webengine模塊,發布程序的時候帶上QtWebEngineProcess.exe+translations文件夾+resources文件夾。

  6. a.setAttribute(Qt::AA_NativeWindows);可以讓每個控件都擁有獨立的句柄。

  7. Qt+Android防止程序被關閉。

#if defined(Q_OS_ANDROID)
QAndroidService a(argc, argv);
return a.exec()
#else
QApplication a(argc, argv);
return a.exec();
#endif
  1. 可以對整體的指示器設置樣式,例如 ::down-arrow,::menu-indicator{} ::up-arrow:disabled,::up-arrow:off{}。

  2. 可以執行位置設置背景圖片。

QMainWindow > .QWidget {
    background-color: gainsboro;
    background-image: url(:/images/pagefold.png);
    background-position: top right;
    background-repeat: no-repeat
}
  1. 嵌入式linux運行Qt程序 Qt4寫法:./HelloQt -qws & Qt5寫法:./HelloQt --platform xcb

  2. Qtcreator軟件的配置文件存放在:C:\Users\Administrator\AppData\Roaming\QtProject,有時候如果發現出問題了,將這個文件夾刪除后打開creator自動重新生成即可。

  3. QMediaPlayer依賴本地解碼器,WIN上下載k-lite或者LAV Filters安裝即可。

  4. 判斷編譯器類型、編譯器版本、操作系統。

//GCC編譯器
#ifdef __GNUC__
#if __GNUC__ >= 3 // GCC3.0以上

//MSVC編譯器
#ifdef _MSC_VER
#if _MSC_VER >=1000 // VC++4.0以上
#if _MSC_VER >=1100 // VC++5.0以上
#if _MSC_VER >=1200 // VC++6.0以上
#if _MSC_VER >=1300 // VC2003以上
#if _MSC_VER >=1400 // VC2005以上
#if _MSC_VER >=1500 // VC2008以上
#if _MSC_VER >=1600 // VC2010以上
#if _MSC_VER >=1700 // VC2012以上
#if _MSC_VER >=1800 // VC2013以上
#if _MSC_VER >=1900 // VC2015以上

//Borland C++
#ifdef __BORLANDC__

//Cygwin
#ifdef __CYGWIN__
#ifdef __CYGWIN32__

//mingw
#ifdef __MINGW32__

//windows
#ifdef _WIN32    //32bit
#ifdef _WIN64    //64bit
#ifdef _WINDOWS     //圖形界面程序
#ifdef _CONSOLE     //控制台程序
//Windows(95/98/Me/NT/2000/XP/Vista)和Windows CE都定義了
#if (WINVER >= 0x030a)     // Windows 3.1以上
#if (WINVER >= 0x0400)     // Windows 95/NT4.0以上
#if (WINVER >= 0x0410)     // Windows 98以上
#if (WINVER >= 0x0500)     // Windows Me/2000以上
#if (WINVER >= 0x0501)     // Windows XP以上
#if (WINVER >= 0x0600)     // Windows Vista以上
//_WIN32_WINNT 內核版本
#if (_WIN32_WINNT >= 0x0500) // Windows 2000以上
#if (_WIN32_WINNT >= 0x0501) // Windows XP以上
#if (_WIN32_WINNT >= 0x0600) // Windows Vista以上

  1. 在pro中判斷不同平台:message($$QT_ARCH) contains(QT_ARCH,arm)。

  2. Qt最小化后恢復界面假死凍結,加上代碼

void showEvent(QShowEvent *e){
setAttribute(Qt::WA_Mapped);
QWidget::showEvent(e);
}
  1. 獲取標題欄高度:style()->pixelMetric(QStyle::PM_TitleBarHeight); PM_TitleBarHeight點進去你會發現新大陸。

  2. 設置高分屏屬性以便支持2K4K等高分辨率,尤其是手機app。必須寫在main函數的QApplication a(argc, argv);的前面。

#if (QT_VERSION > QT_VERSION_CHECK(5,6,0))
    QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
  1. 如果運行程序出現 Fault tolerant heap shim applied to current process. This is usually due to previous crashes. 錯誤。
    辦法:打開注冊表,找到HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers\,選中Layers鍵值,從右側列表中刪除自己的那個程序路徑即可。

  2. Qt內置了QFormLayout表單布局用於自動生成標簽+輸入框的組合的表單界面。

  3. qml播放視頻在linux需要安裝 sudo apt-get install libpulse-dev。

  4. 可以直接繼承QSqlQueryModel實現自定義的QueryModel,比如某一列字體顏色,占位符,其他樣式等,重寫QVariant CustomSqlModel::data(const QModelIndex &index, int role) const。

  5. Qt5以后提供了類QScroller直接將控件滾動。

//禁用橫向滾動條
ui->listWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
//禁用縱向滾動條
ui->listWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
//設置橫向按照像素值為單位滾動
ui->listWidget->setHorizontalScrollMode(QListWidget::ScrollPerPixel);
//設置縱向按照像素值為單位滾動
ui->listWidget->setVerticalScrollMode(QListWidget::ScrollPerPixel);
//設置滾動對象以及滾動方式為鼠標左鍵拉動滾動
QScroller::grabGesture(ui->listWidget, QScroller::LeftMouseButtonGesture);
//還有個QScrollerProperties可以設置滾動的一些參數
  1. 如果使用sqlite數據庫不想產生數據庫文件,可以創建內存數據庫。
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(":memory:");
  1. 清空數據表並重置自增ID,sql = truncate table table_name。

  2. Qtchart模塊從Qt5.7開始自帶,最低編譯要求Qt5.4。在安裝的時候記得勾選,默認不勾選。使用該模塊需要引入命名空間。

#include <QChartView>
QT_CHARTS_USE_NAMESPACE
class CustomChart : public QChartView
  1. QPushButton左對齊文字,需要設置樣式表QPushButton{text-align:left;}

  2. QLabel有三種設置文本的方法,掌握好Qt的屬性系統,舉一反三,可以做出很多效果。

ui->label->setStyleSheet("qproperty-text:hello;");
ui->label->setProperty("text", "hello");
ui->label->setText("hello");
  1. 巧妙的用QEventLoop開啟事件循環,可以使得很多同步獲取返回結果而不阻塞界面。QEventLoop內部新建了線程執行。
QEventLoop loop;
connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
  1. 多種預定義變量 #if (defined webkit) || (defined webengine),去掉生成空的debug和release目錄 CONFIG -= debug_and_release。

  2. 新版的Qtcreator增強了語法檢查,會彈出很多警告提示等,可以在插件列表中關閉clang打頭的幾個即可,Help》About Plugins。也可以設置代碼檢查級別,Tools》Options 》C++ 》Code Model。

  3. QSqlTableModel的rowCount方法,默認最大返回256,如果超過256,可以將表格拉到底部,會自動加載剩余的,每次最大加載256條數據,如果需要打印或者導出數據,記得最好采用sql語句去查詢,而不是使用QSqlTableModel的rowCount方法。不然永遠最大只會導出256條數據。
    如果數據量很小,也可以采用如下方法:

//主動加載所有數據,不然獲取到的行數<=256
while(model->canFetchMore()) {
    model->fetchMore();
}
  1. 如果需要指定無邊框窗體,但是又需要保留操作系統的邊框特性,可以自由拉伸邊框,可以使用 setWindowFlags(Qt::CustomizeWindowHint);

  2. 在某些http post數據的時候,如果采用的是&字符串連接的數據發送,中文解析亂碼的話,需要將中文進行URL轉碼。

QString content = "測試中文";
QString note = content.toUtf8().toPercentEncoding();
  1. Qt默認不支持大資源文件,比如添加了字體文件,需要pro文件開啟。
    CONFIG += resources_big

  2. Qt中繼承QWidget之后,樣式表不起作用,解決辦法有三個。強烈推薦方法一。
    方法一:設置屬性 this->setAttribute(Qt::WA_StyledBackground, true);
    方法二:改成繼承QFrame,因為QFrame自帶paintEvent函數已做了實現,在使用樣式表時會進行解析和繪制。
    方法三:重新實現QWidget的paintEvent函數時,使用QStylePainter繪制。

void myclass::paintEvent(QPaintEvent *)
{
    QStyleOption o;
    o.initFrom(this);
    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_Widget, &o, &p, this);
}
  1. 有時候在界面上加了彈簧,需要動態改變彈簧對應的拉伸策略,對應方法為changeSize,很多人會選擇使用set開頭去找,找不到的。

  2. 在使用QFile的過程中,不建議頻繁的打開文件寫入然后再關閉文件,比如間隔5ms輸出日志,IO性能瓶頸很大,這種情況建議先打開文件不要關閉,等待合適的時機比如析構函數中或者日期變了需要重新變換日志文件的時候關閉文件。不然短時間內大量的打開關閉文件會很卡,文件越大越卡。

  3. 在很多網絡應用程序,需要自定義心跳包來保持連接,不然斷電或者非法關閉程序,對方識別不到,需要進行超時檢測,但是有些程序沒有提供心跳協議,此時需要啟用系統層的保活程序,此方法適用於TCP連接。

int fd = tcpSocket->socketDescriptor();
int keepAlive = 1;      //開啟keepalive屬性,缺省值:0(關閉)
int keepIdle = 5;       //如果在5秒內沒有任何數據交互,則進行探測,缺省值:7200(s)
int keepInterval = 2;   //探測時發探測包的時間間隔為2秒,缺省值:75(s)
int keepCount = 2;      //探測重試的次數,全部超時則認定連接失效,缺省值:9(次)
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepAlive, sizeof(keepAlive));
setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, (void *)&keepIdle, sizeof(keepIdle));
setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, (void *)&keepInterval, sizeof(keepInterval));
setsockopt(fd, SOL_TCP, TCP_KEEPCNT, (void *)&keepCount, sizeof(keepCount));
  1. 如果程序打包好以后彈出提示 This application failed to start because it could not find or load the Qt platform plugin 一般都是因為platforms插件目錄未打包或者打包錯了的原因導致的。

  2. 非常不建議tr中包含中文,盡管現在的新版Qt支持中文到其他語言的翻譯,但是很不規范,也不知道TMD是誰教的,tr的本意是包含英文,然后翻譯到其他語言比如中文,現在大量的初學者濫用tr,如果沒有翻譯的需求,禁用tr,tr需要開銷的,Qt默認會認為他需要翻譯,會額外進行特殊處理。

  3. 很多人Qt和Qt Creator傻傻分不清楚,經常問Qt什么版本結果發一個Qt Creator的版本過來,Qt Creator是使用Qt編寫的集成開發環境IDE,和宇宙第一的Visual Studio一樣,他可以是msvc編譯器的(WIN對應的Qt集成安裝環境中自帶的Qt Cerator是msvc的),也可以是mingw編譯的,還可以是gcc的。如果是自定義控件插件,需要集成到Qt Creator中,必須保證該插件的動態庫文件(dll或者so等文件)對應的編譯器和Qt版本以及位數和Qt Creator的版本完全一致才行,否則基本不大可能集成進去。特別注意的是Qt集成環境安裝包中的Qt版本和Qt Creator版本未必完全一致,必須擦亮眼睛看清楚,有些是完全一致的。

  4. 超過兩處相同處理的代碼,建議單獨寫成函數。代碼盡量規范精簡,比如 if(a == 123) 要寫成 if (123 == a),值在前面,再比如 if (ok == true) 要寫成 if (ok),if (ok == false) 要寫成 if (!ok)等。

  5. 很多人問Qt嵌入式平台用哪個好,這里統一回答(當前時間節點2018年):imx6+335x比較穩定,性能高就用RK3288 RK3399,便宜的話就用全志H3,玩一玩可以用樹莓派香橙派。

  6. 對於大段的注釋代碼,建議用 #if 0 #endif 將代碼塊包含起來,而不是將該段代碼選中然后全部 // ,下次要打開這段代碼的話,又需要重新選中一次取消,如果采用的是 #if 0則只要把0改成1即可,效率大大提升。

  7. Qt打包發布,有很多辦法,Qt5以后提供了打包工具windeployqt(linux上為linuxdeployqt,mac上為macdeployqt)可以很方便的將應用程序打包,使用下來發現也不是萬能的,有時候會多打包一些沒有依賴的文件,有時候又會忘記打包一些插件尤其是用了qml的情況下,而且不能識別第三方庫,比如程序依賴ffmpeg,則對應的庫需要自行拷貝,終極大法就是將你的可執行文件復制到Qt安裝目錄下的bin目錄,然后整個一起打包,挨個刪除不大可能依賴的組件,直到刪到正常運行為止。

  8. Qt中的動畫,底層用的是QElapsedTimer定時器來完成處理,比如產生一些指定規則算法的數據,然后對屬性進行處理。

  9. 在繪制無背景顏色只有邊框顏色的圓形時候,可以用繪制360度的圓弧替代,效果完全一致。

QRect rect(-radius, -radius, radius * 2, radius * 2);
//以下兩種方法二選一,其實繪制360度的圓弧=繪制無背景的圓形
painter->drawArc(rect, 0, 360 * 16);
painter->drawEllipse(rect);
  1. 不要把d指針看的很玄乎,其實就是在類的實現文件定義了一個私有類,用來存放局部變量,個人建議在做一些小項目時,沒有太大必要引入這種機制,會降低代碼可讀性,增加復雜性,新手接受項目后會看的很懵逼。

  2. 很多人在繪制的時候,設置畫筆以為就只可以設置個單調的顏色,其實QPen還可以設置brush,這樣靈活性就提高不知道多少倍,比如設置QPen的brush以后,可以使用各種漸變,比如繪制漸變顏色的進度條和文字等,而不再是單調的一種顏色。

  3. 很多控件都帶有viewport,比如QTextEdit/QTableWidget/QScrollArea,有時候對這些控件直接處理的時候發現不起作用,需要對其viewport()設置才行,比如設置滾動條區域背景透明,需要使用scrollArea->viewport()->setStyleSheet("background-color:transparent;");而不是scrollArea->setStyleSheet("QScrollArea{background-color:transparent;}");

  4. 有時候設置了鼠標跟蹤setMouseTracking為真,如果該窗體上面還有其他控件,當鼠標移到其他控件上面的時候,父類的鼠標移動事件MouseMove識別不到了,此時需要用到HoverMove事件,需要先設置 setAttribute(Qt::WA_Hover, true);

  5. Qt封裝的QDateTime日期時間類非常強大,可以字符串和日期時間相互轉換,也可以毫秒數和日期時間相互轉換,還可以1970經過的秒數和日期時間相互轉換等。

QDateTime dateTime;
QString dateTime_str = dateTime.currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
//從字符串轉換為毫秒(需完整的年月日時分秒)
datetime.fromString("2011-09-10 12:07:50:541", "yyyy-MM-dd hh:mm:ss:zzz").toMSecsSinceEpoch();
//從字符串轉換為秒(需完整的年月日時分秒)
datetime.fromString("2011-09-10 12:07:50:541", "yyyy-MM-dd hh:mm:ss:zzz").toTime_t();
//從毫秒轉換到年月日時分秒
datetime.fromMSecsSinceEpoch(1315193829218).toString("yyyy-MM-dd hh:mm:ss:zzz");
//從秒轉換到年月日時分秒(若有zzz,則為000)
datetime.fromTime_t(1315193829).toString("yyyy-MM-dd hh:mm:ss[:zzz]");
  1. 在我們使用QList、QStringList、QByteArray等鏈表或者數組的過程中,如果只需要取值,而不是賦值,強烈建議使用 at() 取值而不是 [] 操作符,在官方書籍《C++ GUI Qt 4編程(第二版)》的書中有特別的強調說明,此教材的原作者據說是Qt開發的核心人員編寫的,所以還是比較權威,至於使用 at() 與使用 [] 操作符速度效率的比較,網上也有網友做過此類對比。原文在書的212頁,這樣描述的:Qt對所有的容器和許多其他類都使用隱含共享,隱含共享是Qt對不希望修改的數據決不進行復制的保證,為了使隱含共享的作用發揮得最好,可以采用兩個新的編程習慣。第一種習慣是對於一個(非常量的)向量或者列表進行只讀存取時,使用 at() 函數而不用 [] 操作符,因為Qt的容器類不能辨別 [] 操作符是否將出現在一個賦值的左邊還是右邊,他假設最壞的情況出現並且強制執行深層賦值,而 at() 函數則不被允許出現在一個賦值的左邊。

  2. 如果是dialog窗體,需要在exec以后還能讓其他代碼繼續執行,請在dialog窗體exec前增加一行代碼,否則會阻塞窗體消息。

QDialog dialog;
dialog.setWindowModality(Qt::WindowModal);
dialog.exec();
  1. 安全的刪除Qt的對象類,強烈建議使用deleteLater而不是delete,因為deleteLater會選擇在合適的時機進行釋放,而delete會立即釋放,很可能會出錯崩潰。如果要批量刪除對象集合,可以用qDeleteAll,比如 qDeleteAll(btns);

  2. 在QTableView控件中,如果需要自定義的列按鈕、復選框、下拉框等其他模式顯示,可以采用自定義委托QItemDelegate來實現,如果需要禁用某列,則在自定義委托的重載createEditor函數返回0即可。自定義委托對應的控件在進入編輯狀態的時候出現,如果想一直出現,則需要重載paint函數用drawPrimitive或者drawControl來繪制。

  3. 將 QApplication::style() 對應的drawPrimitive、drawControl、drawItemText、drawItemPixmap等幾個方法用熟悉了,再結合QStyleOption屬性,可以玩轉各種自定義委托,還可以直接使用paint函數中的painter進行各種繪制,各種牛逼的表格、樹狀列表、下拉框等,絕對屌炸天。QApplication::style()->drawControl 的第4個參數如果不設置,則繪制出來的控件不會應用樣式表。

  4. 心中有坐標,萬物皆painter,強烈建議在學習自定義控件繪制的時候,將qpainter.h頭文件中的函數全部看一遍、試一遍、理解一遍,這里邊包含了所有Qt內置的繪制的接口,對應的參數都試一遍,你會發現很多新大陸,會大大激發你的繪制的興趣,猶如神筆馬良一般,策馬崩騰遨游代碼繪制的世界。

  5. 在使用setItemWidget或者setCellWidget的過程中,有時候會發現設置的控件沒有居中顯示而是默認的左對齊,而且不會自動拉伸填充,對於追求完美的程序員來說,這個可不大好看,有個終極通用辦法就是,將這個控件放到一個widget的布局中,然后將widget添加到item中,這樣就完美解決了,而且這樣可以組合多個控件產生復雜的控件。

//實例化進度條控件
QProgressBar *progress = new QProgressBar;
//增加widget+布局巧妙實現居中
QWidget *widget = new QWidget;
QHBoxLayout *layout = new QHBoxLayout;
layout->setSpacing(0);
layout->setMargin(0);
layout->addWidget(progress);
widget->setLayout(layout);
ui->tableWidget->setCellWidget(0, 0, widget);
  1. 很多時候需要在已知背景色的情況下,能夠清晰的繪制文字,這個時候需要計算對應的文字顏色。
//根據背景色自動計算合適的前景色
double gray = (0.299 * color.red() + 0.587 * color.green() + 0.114 * color.blue()) / 255;
QColor textColor = gray > 0.5 ? Qt::black : Qt::white;
  1. 對QTableView或者QTableWidget禁用列拖動。
#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0))
    ui->tableView->horizontalHeader()->setResizeMode(0, QHeaderView::Fixed);
#else
    ui->tableView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed);
#endif
  1. 從Qt4轉到Qt5,有些類的方法已經廢棄或者過時了,如果想要在Qt5中啟用Qt4的方法,比如QHeadVew的setMovable,可以在你的pro或者pri文件中加上一行即可:DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0

  2. Qt中的QColor對顏色封裝的很完美,支持各種轉換,比如rgb、hsb、cmy、hsl,對應的是toRgb、toHsv、toCmyk、toHsl,還支持透明度設置,顏色值還能轉成16進制格式顯示。

QColor color(255, 0, 0, 100);
qDebug() << color.name() << color.name(QColor::HexArgb);
//輸出 #ff0000 #64ff0000
  1. QVariant類型異常的強大,可以說是萬能的類型,在進行配置文件的存儲的時候,經常會用到QVariant的轉換,QVariant默認自帶了toString、toFloat等各種轉換,但是還是不夠,比如有時候需要從QVariant轉到QColor,而卻沒有提供toColor的函數,這個時候就要用到萬能辦法。
if (variant.typeName() == "QColor") {
    QColor color = variant.value<QColor>();
    QFont font = variant.value<QFont>();
    QString nodeValue = color.name(QColor::HexArgb);
}
  1. Qt中的QString和const char *之間轉換,最好用toStdString().c_str()而不是toLocal8Bit().constData(),比如在setProperty中如果用后者,字符串中文就會不正確,英文正常。

  2. Qt的信號槽機制非常牛逼,也是Qt的獨特的核心功能之一,有時候我們在很多窗體中傳遞信號來實現更新或者處理,如果窗體層級比較多,比如窗體A的父類是窗體B,窗體B的父類是窗體C,窗體C有個子窗體D,如果窗體A一個信號要傳遞給窗體D,問題來了,必須先經過窗體B中轉到窗體C再到窗體D才行,這樣的話各種信號關聯信號的connect會非常多而且管理起來比較亂,可以考慮增加一個全局的單例類AppEvent,公共的信號放這里,然后窗體A對應信號綁定到AppEvent,窗體D綁定AppEvent的信號到對應的槽函數即可,干凈清爽整潔。

  3. QTextEdit右鍵菜單默認英文的,如果想要中文顯示,加載widgets.qm文件即可,一個Qt程序中可以安裝多個翻譯文件,不沖突。

  4. Qt中有個全局的焦點切換信號focusChanged,可以用它做自定義的輸入法。Qt4中默認會安裝輸入法上下文,比如在main函數打印a.inputContext會顯示值,這個默認安裝的輸入法上下文,會攔截兩個牛逼的信號QEvent::RequestSoftwareInputPanel和QEvent::CloseSoftwareInputPanel,以至於就算你安裝了全局的事件過濾器依然識別不到這兩個信號,你只需要在main函數執行a.setInputContext(0)即可,意思是安裝輸入法上下文為空。

  5. 在Qt5.10以后,表格控件QTableWidget或者QTableView的默認最小列寬改成了15,以前的版本是0,所以在新版的qt中,如果設置表格的列寬過小,不會應用,取的是最小的列寬。所以如果要設置更小的列寬需要重新設置ui->tableView->horizontalHeader()->setMinimumSectionSize(0);

  6. Qt源碼中內置了一些未公開的不能直接使用的黑科技,都藏在對應模塊的private中,比如gui-private widgets-private等,比如zip文件解壓類QZipReader、壓縮類QZipWriter就在gui-private模塊中,需要在pro中引入QT += gui-private才能使用。

#include "QtGui/private/qzipreader_p.h"
#include "QtGui/private/qzipwriter_p.h"

QZipReader reader(dirPath);
QString path("");
//解壓文件夾到當前目錄
reader.extractAll(path);
//文件夾名稱
QZipReader::FileInfo fileInfo = reader.entryInfoAt(0);
//解壓文件
QFile file(filePath);
file.open(QIODevice::WriteOnly);
file.write(reader.fileData(QString::fromLocal8Bit("%1").arg(filePath)));
file.close();
reader.close();

QZipWriter *writer = new QZipWriter(dirPath);
//添加文件夾
writer->addDirectory(unCompress);
//添加文件
QFile file(filePath);
file.open(QIODevice::ReadOnly);
writer->addFile(data, file.readAll());
file.close();
writer->close();
  1. 理論上串口和網絡收發數據都是默認異步的,操作系統自動調度,完全不會卡住界面,網上那些說收發數據卡住界面主線程的都是扯幾把蛋,真正的耗時是在運算以及運算后的處理,而不是收發數據,在一些小數據量運算處理的項目中,一般不建議動用線程去處理,線程需要調度開銷的,不要什么東西都往線程里邊扔,線程不是萬能的。只有當真正需要將一些很耗時的操作比如編碼解碼等,才需要移到線程處理。

  2. 在構造函數中獲取控件的寬高很可能是不正確的,需要在控件首次顯示以后再獲取才是正確的,控件是在首次顯示以后才會設置好正確的寬高值,記住是在首次顯示以后,而不是構造函數或者程序啟動好以后,如果程序啟動好以后有些容器控件比如QTabWidget中的沒有顯示的頁面的控件,你去獲取寬高很可能也是不正確的,萬無一失的辦法就是首次顯示以后去獲取。

  3. 數據庫處理一般建議在主線程,如果非要在其他線程,務必記得打開數據庫也要在那個線程,即在那個線程使用數據庫就在那個線程打開,不能打開數據庫在主線程,執行sql在子線程,很可能出問題。

  4. 新版的QTcpServer類在64位版本的Qt下很可能不會進入incomingConnection函數,那是因為Qt5對應的incomingConnection函數參數變了,由之前的int改成了qintptr,改成qintptr有個好處,在32位上自動是quint32而在64位上自動是quint64,如果在Qt5中繼續寫的參數是int則在32位上沒有問題在64位上才有問題,所以為了兼容Qt4和Qt5,必須按照不一樣的參數寫。

#if (QT_VERSION > QT_VERSION_CHECK(5,0,0))
    void incomingConnection(qintptr handle);
#else
    void incomingConnection(int handle);
#endif
  1. Qt支持所有的界面控件比如QPushButton、QLineEdit自動關聯 on_控件名_信號(參數) 信號槽,比如按鈕的單擊信號 on_pushButton_clicked(),然后直接實現槽函數即可。

  2. QWebEngineView控件由於使用了opengl,在某些電腦上可能由於opengl的驅動過低會導致花屏或者各種奇奇怪怪的問題,比如showfullscreen的情況下鼠標右鍵失效,需要在main函數啟用軟件opengl渲染。

#if (QT_VERSION > QT_VERSION_CHECK(5,4,0))
    QCoreApplication::setAttribute(Qt::AA_UseSoftwareOpenGL);
#endif
    QApplication a(argc, argv);

另外一個方法解決 全屏+QWebEngineView控件一起會產生右鍵菜單無法彈出的BUG,需要上移一個像素

QRect rect = qApp->desktop()->geometry();
rect.setY(-1);
rect.setHeight(rect.height());
this->setGeometry(rect);
  1. QStyle內置了很多方法用處很大,比如精確獲取滑動條鼠標按下處的值。
QStyle::sliderValueFromPosition(minimum(), maximum(), event->x(), width());
  1. 用QFile讀寫文件的時候,推薦用QTextStream文件流的方式來讀寫文件,速度快很多,基本上會有30%的提升,文件越大性能區別越大。
//從文件加載英文屬性與中文屬性對照表
QFile file(":/propertyname.txt");
if (file.open(QFile::ReadOnly)) {
    //QTextStream方法讀取速度至少快30%
#if 0
    while(!file.atEnd()) {
        QString line = file.readLine();
        appendName(line);
    }
#else
    QTextStream in(&file);
    while (!in.atEnd()) {
        QString line = in.readLine();
        appendName(line);
    }
#endif
    file.close();
}
  1. QSS文件不支持UTF8,切記不要在QtCreator中打開qss文件來編輯保存,這樣很可能導致qss加載以后沒有效果,你需要保存為ANSI格式。

  2. QString內置了很多轉換函數,比如可以調用toDouble轉為double數據,但是當你轉完並打印的時候你會發現精確少了,只剩下三位了,其實原始數據還是完整的精確度的,只是打印的時候優化成了三位,如果要保證完整的精確度,可以調用 qSetRealNumberPrecision 函數設置精確度位數即可。

QString s1, s2;
s1 = "666.5567124";
s2.setNum(888.5632123, 'f', 7);
qDebug() << qSetRealNumberPrecision(10) << s1.toDouble() << s2.toDouble();

二、其他經驗

  1. Qt界的中文亂碼問題,版本眾多導致的如何選擇安裝包問題,如何打包發布程序的問題,堪稱Qt界的三座大山!

  2. 在Qt的學習過程中,學會查看對應類的頭文件是一個好習慣,如果在該類的頭文件沒有找到對應的函數,可以去他的父類中找找,實在不行還有爺爺類,肯定能找到的。通過頭文件你會發現很多函數接口其實Qt已經幫我們封裝好了,有空還可以閱讀下他的實現代碼。

  3. Qt安裝目錄下的Examples目錄下的例子,看完學完,月薪20K起步;Qt常用類的頭文件的函數看完學完使用一遍並加以融會貫通,月薪30K起步。

  4. Qt在開發階段不支持中文目錄,切記,這是無數人可能犯的錯誤,在安裝Qt集成開發環境以及編譯器的時候,務必記得目錄必須英文,否則很可能不正常,建議盡量用默認的安裝位置。

  5. 如果出現崩潰和段錯誤,80%都是因為要么越界,要么未初始化,死扣這兩點,80%的問題解決了。

  6. Qt一共有幾百個版本,關於如何選擇Qt版本的問題,我一般保留四個版本,為了兼容Qt4用4.8.7,最后的支持XP的版本5.7.0,最新的長期支持版本比如5.9.8,最高的新版本比如5.13.1。強烈不建議使用5.0到5.3之間的版本,太多BUG和坑,穩定性和兼容性相比於之后的版本相當差,能換就換,不能換睡服領導也要換。

  7. 終極秘籍:如果遇到問題搜索Qt方面找不到答案,試着將關鍵字用JAVA C# android打頭,你會發現別有一番天地,其他人很可能做過!

  8. 最后一條:珍愛生命,遠離編程。祝大家頭發濃密,睡眠良好,情緒穩定,財富自由!

三、推薦的Qt論壇+個人博客+網站

名稱 網址
QtWidget開源demo集合 https://gitee.com/feiyangqingyun/QWidgetDemo
QtQuick/Qml開源demo集合 https://gitee.com/jaredtao/TaoQuick
qtcn http://www.qtcn.org
豆子的空間 https://www.devbean.net
yafeilinux http://www.qter.org
一去二三里 http://blog.csdn.net/liang19890820
烏托邦2號 http://blog.csdn.net/taiyang1987912
foruok http://blog.csdn.net/foruok
jason http://blog.csdn.net/wsj18808050
朝十晚八 http://www.cnblogs.com/swarmbees
BIG_C_GOD http://blog.csdn.net/big_c_god
公孫二狗 https://qtdebug.com/qtbook
雨田哥 https://blog.csdn.net/ly305750665
鄭天佐 https://blog.csdn.net/zhengtianzuo06
寒山-居士 https://blog.csdn.net/esonpo
feiyangqingyun https://blog.csdn.net/feiyangqingyun
前行中小豬 http://blog.csdn.net/goforwardtostep
濤哥的知乎專欄 https://zhuanlan.zhihu.com/TaoQt
Qt君 https://blog.csdn.net/nicai_xiaoqinxi
Qt老外視頻教程 http://space.bilibili.com/2592237/#!/index
Qt維基補充文檔 https://wiki.qt.io/Main
Qt源碼查看網站 https://code.woboq.org/qt5
Qt官方下載地址 https://download.qt.io
Qt官方下載新地址 https://download.qt.io/new_archive/qt/
Qt國內鏡像下載地址 https://mirrors.cloud.tencent.com/qt
精美圖表控件QWT http://qwt.sourceforge.net/
精美圖表控件QCustomPlot https://www.qcustomplot.com/
免費圖標下載 http://www.easyicon.net/
圖形字體下載 https://www.iconfont.cn/
漂亮界面網站 https://www.ui.cn/

三、其他

  1. Qt入門書籍推薦霍亞飛的《Qt Creator快速入門》,Qt進階書籍推薦官方的《C++ GUI Qt4編程》,qml書籍推薦《Qt5編程入門》。
  2. 強烈推薦程序員自我修養和規划系列書《大話程序員》《程序員的成長課》《解憂程序員》,受益匪淺,受益終生!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM