Qt開發經驗小技巧171-175

  1. 在Qt編程中經常會遇到編碼的問題,由於跨平臺的考慮兼容各種系統,而windows系統默認是gbk或者gb2312編碼,當然後期可能msvc編譯器都支持utf8編碼,所以在部分程序中傳入中文目錄文件名稱的時候會發現失敗,因爲可能對應的接口用了早期的fopen函數而不是fopen_s函數,比如fmod中也是這個情況。這個時候就需要轉碼處理。
QString fileName = "c:/測試目錄/1.txt";
//如果應用程序main函數中沒有設置編碼則默認採用系統的編碼,可以直接通過toLocal8Bit轉成正確的數據
const char *name = fileName.toLocal8Bit().constData();

//如果設置過了下面兩句則需要主動轉碼
QTextCodec *codec = QTextCodec::codecForName("utf-8");
QTextCodec::setCodecForLocale(codec);

QTextCodec *code = QTextCodec::codecForName("gbk");
const char *name = code->fromUnicode(fileName).constData();

//推薦方式2以防萬一保證絕對的正確,哪怕是設置過主程序的編碼
//切記一旦設置過QTextCodec::setCodecForLocale會影響toLocal8Bit

//有時候可能還有下面這種情況
#ifdef Q_OS_WIN
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
    QTextCodec *code = QTextCodec::codecForName("utf-8");
#else
    QTextCodec *code = QTextCodec::codecForName("gbk");
#endif
    const char *name = code->fromUnicode(fileName).constData();
#else
    const char *name = fileName.toUtf8().constData();
#endif
  1. 在查閱和學習Qt源碼的過程中,發現了一些趨勢和改變。
  • 數據類型這塊儘量用Qt內部的數據類型,哪怕是重定義過的比如quint8其實unsigned char,qreal就是double,以前翻看源碼的時候可能還有些是double,現在慢慢改成了qreal。
  • 循環結構用 for(;;) 替代 while(1),因爲轉成彙編指令後 for(;;) 只有一條指令而 while(1) 確有4條,指令少不佔用寄存器而且不用跳轉,理論上速度要更快。
  • 其實Qt中就重定義了 forever 關鍵字表示 for(;;) ,我的乖乖,想的真周到。
  • 自動c++11以及後續的標準都支持auto萬能數據類型,發現Qt的源碼中也慢慢的改成了auto,這樣加快了編寫代碼的效率,不用自己去指定數據類型而是讓編譯器自己推導數據類型。而且其實也不影響編譯器編譯的速度,因爲無論指定和沒有指定數據類型,編譯器都要推導右側的數據類型進行判斷。不過有個缺點就是影響了閱讀代碼的成本,很多時候需要自己去理解推導。
  1. Qt中設置或者打開加載本地文件需要用到QUrl類,本地文件建議加上 file:/// 前綴。
QString url = "file:///c:/1.html";
//瀏覽器控件打開本地網頁文件
webView->setUrl(QUrl(url));
//打開本地網頁文件,下面兩種方法都可以
QDesktopServices::openUrl(QUrl::fromLocalFile(url));
QDesktopServices::openUrl(QUrl(url, QUrl::TolerantMode));
  1. 在網絡請求中經常涉及到超時時間的問題,因爲默認是30秒鐘,一旦遇到網絡故障的時候要等好久才能反應過來,所以需要主動設置下超時時間,超過了就直接中斷結束請求。從Qt5.15開始內置了setTransferTimeout來設置超時時間,非常好用。
//局部的事件循環,不卡主界面
QEventLoop eventLoop;

//設置超時 5.15開始自帶了超時時間函數 默認30秒
#if (QT_VERSION >= QT_VERSION_CHECK(5,15,0))
manager->setTransferTimeout(timeout);
#else
QTimer timer;
connect(&timer, SIGNAL(timeout()), &eventLoop, SLOT(quit()));
timer.setSingleShot(true);
timer.start(timeout);
#endif

QNetworkReply *reply = manager->get(QNetworkRequest(QUrl(url)));
connect(reply, SIGNAL(finished()), &eventLoop, SLOT(quit()));
eventLoop.exec();

if (reply->bytesAvailable() > 0 && reply->error() == QNetworkReply::NoError) {
    //讀取所有數據保存成文件
    QByteArray data = reply->readAll();
    QFile file(dirName + fileName);
    if (file.open(QFile::WriteOnly | QFile::Truncate)) {
        file.write(data);
        file.close();
    }
}
  1. Qt中基本上有三大類型的項目,控制檯項目對應QCoreApplication、傳統QWidget界面程序對應QApplication、quick/qml項目程序對應QGuiApplication。有很多屬性的開啓需要在main函數的最前面執行纔有效果,比如開啓高分屏支持、設置opengl模式等。不同類型的項目需要對應的QApplication。
//如果是控制檯程序則下面的QApplication換成QCoreApplication
//如果是quick/qml程序則下面的QApplication換成QGuiApplication
int main(int argc, char *argv[])
{
    //可以用下面這行測試Qt自帶的輸入法 qtvirtualkeyboard
    qputenv("QT_IM_MODULE", QByteArray("qtvirtualkeyboard"));
    
    //設置不應用操作系統設置比如字體
    QApplication::setDesktopSettingsAware(false);

#if (QT_VERSION >= QT_VERSION_CHECK(6,0,0))
    //設置高分屏縮放舍入策略
    QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::Floor);
#endif
#if (QT_VERSION > QT_VERSION_CHECK(5,6,0))
    //設置啓用高分屏縮放支持
    //要注意開啓後計算到的控件或界面寬度高度可能都不對,全部需要用縮放比例運算下
    QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    //設置啓用高分屏圖片支持
    QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#endif
#if (QT_VERSION > QT_VERSION_CHECK(5,4,0))
    //設置opengl模式 AA_UseDesktopOpenGL(默認) AA_UseSoftwareOpenGL AA_UseOpenGLES
    //QApplication::setAttribute(Qt::AA_UseSoftwareOpenGL);
    //設置opengl共享上下文
    QApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
#endif

    QApplication a(argc, argv);
    QWidget w;
    w.show();
    return a.exec();
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章