Qt4问题集锦
一、Qt程序發布后加載的jpg、jpeg圖片不可見
問題的提出:
最近在客戶機器上部署安裝QT編寫的軟件,發現只要是jpg、jpeg格式的圖片都無法顯示出來。最后發現必須按如下述步驟才能顯示jpg、jpeg格式的圖片: 1、 在你主啟動程序即exe同一目錄下新建一個目錄,目錄名必須和QT安裝目錄下的imageformats目錄同名。也即新建一個名為imageformats的文件夾。 2 、找到QT安裝目錄下C:\Qt\4.8.5\plugins\imageformats子目錄,將該子目錄下的qjpeg4.dll文件復制到步驟1中新建的imageformats目錄即可。 此時再次啟動主程序,現在發現jpg、jpeg格式的圖片可以顯示出來了。說明:步驟2中紅色路徑我QT的安裝路徑,你的路徑可能和我這不一樣,請自行更改。
?
二、運行Qt程序時碰到QWidget: Must construct a QApplication before a QPaintDevice
問題的提出:
之前編譯Qwt源碼生成qwtd.dll,qwt.dll,然后在工程.pro文件中使用時引入Qwt模塊:
DEFINES += QT_DLL QWT_DLL INCLUDEPATH += C:/QtSDK/Desktop/Qt/4.8.1/mingw/include/Qwt LIBS += -L"C:/QtSDK/Desktop/Qt/4.8.1/mingw/lib" -lqwtd LIBS += -L"C:/QtSDK/Desktop/Qt/4.8.1/mingw/lib" -lqwt結果程序運行時,出現QWidget: Must construct a QApplication before a QPaintDevice
網上搜索的結果是Releases和DEBUG版本的庫混在一起了,雖然他們是不同的名字(Debug版本帶個d),但是一直不明白。我生成release版后,直接運行.exe時發現提示缺少qwtd.dll庫,
此時才發現果然是庫的問題,生成release版卻調用了debug版的庫qwtd.dll。
問題解決:將.pro文件中Qwt模塊引入代碼改為:
DEFINES += QT_DLL QWT_DLL INCLUDEPATH += C:/QtSDK/Desktop/Qt/4.8.1/mingw/include/Qwt CONFIG(debug,debug|release) { unix|win32: LIBS += -L"C:/QtSDK/Desktop/Qt/4.8.1/mingw/lib" -lqwtd } else { unix|win32: LIBS += -L"C:/QtSDK/Desktop/Qt/4.8.1/mingw/lib" -lqwt }此時,編譯成debug版則只會調用qwtd.dll,而生成release版則只會調用qwt.dll。
?
三、Qt編寫上位機一定要初始化變量以及謹慎操作指針(尤其是QWidget控件指針)
背景:在編寫QT上位機界面時,界面在運行的時候經常出現卡死或者直接掛掉的怪現象。
正文:上位機有個函數為check_receive();該函數的作用為定時調用循環檢測USB是否有數據。若有,則將信息打印到界面窗體上。界面上有兩個QTableWidget窗體
"ui->can1tableWidget與ui->can2tableWidget",根據傳上來的的數據某個字節信息為1、或2來打印到對應的窗體上。代碼如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | QTableWidget *canselWidget = NULL; unsigned?int?CANSelCnt; if(CANData.CANSel == 1) { ????CANSelCnt = 第1個窗體顯示的行數;????//偽代碼 ????canselWidget = ui->can1tableWidget ; } else?if(CANData.CANSel == 2) { ????CANSelCnt = 第2個窗體顯示的行數;????//偽代碼 ????canselWidget = ui->can2tableWidget ; } //接著即使用canselWidget來對界面進行操作。 |
接著,總會出現,QT上位機界面直接卡死甚至掛掉的問題。觀察現象發現,APP在顯示數據窗體時即瘋狂地新增新的行數。再研究代碼,然后將CANSelCnt打印出來,發現其值為一個很大的隨機值。
解決方案:CANSelCnt 在定義的時候要初始化!!!
接著運行上位機發現,APP顯示數據窗體不再瘋狂的新增行數了??蛇€是出現掛掉的現象!!
進一步調試才發現若是CANData.CANSel的值不是為1、2那會出現什么情況! 就會對canselWideget這個NULL指針進行操作!更改代碼如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | switch(CANData.CANSel) { ????case?1: ????????CANSelCnt = 第1個窗體顯示的行數;????//偽代碼 ????????canselWidget = ui->can1tableWidget ; ?????????break; ????case?2: ????????CANSelCnt = 第2個窗體顯示的行數;????//偽代碼 ????????canselWidget = ui->can2tableWidget ; ????????break; ????default: ????????// 防止后續代碼對空指針進行操作,直接返回。 ????????return; } |
總結:
1、此處代碼寫的非常不小心,犯如此低級的錯誤卻花費了1天多的時間(還以為是下位機沒配置好!)!下次一定要把握住程序運行的每個通路,杜絕此現象再次發生。
2、由于之前一直在寫下位機代碼,所以不賦初值的習慣也帶入到這里,出了這次慘痛教訓!
?
(以下討論僅針對下位機)在下位機,為何會經常出現不賦初值的情況發生。(應該說是在聲明的時候不會賦初值。)
首先,最重要的是,下位機保存全局變量的區域為掉電易失區域,所以得到的變量值會為默認"0"值,嚴謹的做法還是會初始化全局變量。
其次,在多個".c"文件包含一個".h"文件的情況下,若在".h"文件中賦初值,則相當于在其內即聲明又定義了,那么編譯時,即會出現如下報錯:keil *** ERROR L104: MULTIPLE PUBLIC DEFINITIONS (報錯信息不完整,只挑了重點部分)。所以說有多個".c"文件需要包含該".h"文件時,不能進行變量的定義,只能進行聲明!然后在"main函數"內對其進行初始化操作,否則會出現以上錯誤,即重復定義!
? ? ?那么多個"c"文件包含一個".h"文件具體該如何操作呢?
我自己當時的錯誤想法既是:
在".h"文件內,聲明全局變量、函數,譬如uchar aa;void sum(uchar aa); 然后多個".c"文件#include該".h"文件,結局很顯然,重復定義錯誤跑不掉。
何不使用?#ifndef?#define?#endif ?結果證明并沒有什么卵用。
正確的做法是,
在".c"文件內聲明全局變量、函數,譬如uchar aa;void sum(uchar aa);,并在".c"文件內實現該函數。
然后,在".h"文件,將變量aa,函數void sum(uchar aa);聲明為extern,這樣,其他".c"包含該".h"文件即不會提示重復定義,也可以調用其內部的函數。
其實這種做法其實相當于某個需要調用該".c"文件的其他"XXX.c"文件在其文件內 extern 該“.c"文件內實現的函數及定義的變量。若是多個文件需要使用使用,每個".c"文件都需 extern 同樣的變量和函數,顯然在做重復工作,于是就將它放在一個".h"文件,多個".c"文件需要調用時直接包含該".h"文件就可以實現 extern 了。
總之,要養成良好的編程習慣,編寫下位機時最好不要在.h文件去定義一個變量,更不能在.h文件去初始化變量。變量定義與初始化在.c文件進行,若多個外部.c文件需要調用,則在.h文件中添加extern進行外部聲明即可。
轉載于:https://www.cnblogs.com/King-Gentleman/p/5986331.html
總結
- 上一篇: (转) 一张图解AlphaGo原理及弱点
- 下一篇: 寻找下一款Prisma APP:深度学习