Qt開發經驗小技巧226-230

  1. qtc開發工具內置了不少的函數,可以很方便的進行一些判斷和處理。
//最小版本要求
!minQtVersion(5, 15, 2) {
    message("Cannot build Qt Installer Framework with Qt version $${QT_VERSION}.")
    error("Use at least Qt 5.15.2.")
}
  1. 有時候文本框中的內容過長,而文本框默認光標在尾部,所以要主動設置下將光標移到最前面
//三種方法都可以
ui->lineEdit->setSelection(0, 0);
ui->lineEdit->setCursorPosition(0);
//樣式表方式
"QLineEdit{qproperty-cursorPosition:0;}
  1. 關於Qt瀏覽器模塊的幾點說明。
  • Qt5.6以前用的是webkit,Qt5.6版本以後分兩種情況,一種是mingw編譯器(windows系統)對應的Qt庫不再提供瀏覽器模塊。
  • Qt5.6以後的版本在linux系統和mac等系統,都不存在沒有瀏覽器控件的情況,都使用的是webengine。
  • 僅僅是windows上的mingw編譯器的Qt版本沒有,其他系統其實都有的。很多人在這個地方都有疑問,都以爲只有msvc編譯器有瀏覽器控件,其實確切的說是在windows上msvc的Qt庫帶瀏覽器控件。
  • 安裝Qt的時候webengine模塊默認不勾選,需要主動勾選才會安裝。
  • 也不是所有的msvc的Qt版本都有webengine瀏覽器模塊,哪怕你勾選了也沒用,有些版本官方並沒有編譯,需要自行編譯。需要到對應的Qt安裝目錄查看是否有 Qt5WebEngine.dll 文件。
  • 如果僅僅是爲了彌補mingw版本缺失瀏覽器模塊的遺憾,推薦用miniblink。
  • 如果爲了統一兼容各種版本和系統,推薦用cef。
  • 如果沒有歷史包袱,推薦用webengine,與Qt的集成度高。
  • webkit和miniblink默認都不支持gpu,webengine默認走gpu。
  • qwebengine默認不支持MP4,需要自己重新編譯。
  1. 關於編譯數據庫插件的幾個經驗總結。
  • 安裝對應的數據庫,安裝後會有include頭文件和lib鏈接庫文件,這是基本的前提,編譯數據庫插件必須要有這兩個東西。務必注意,32位的Qt必須安裝32位的數據庫才能正常編譯成功,位數要一致。
  • 準備好數據庫插件源碼,比如qt-everywhere-src-5.14.2\qtbase\src\plugins\sqldrivers\mysql,可以在安裝Qt的時候勾選src,或者後期直接官網重新下載源碼解壓出來。
  • 打開你要編譯的數據庫插件源碼,比如mysql就打開mysql.pro,oracle就打開oci.pro。
  • 在pro中註釋掉一行 #QMAKE_USE += mysql,如果是oci項目則是#QMAKE_USE += oci。
  • qsqldriverbase.pri文件中註釋掉 #include(..shadowed(..PWD)/qtsqldrivers-config.pri)。
  • mysql.pro文件內容下面加上如下代碼。
path = C:/Qt/mysql-5.7.30-winx64
INCLUDEPATH += $$path/include
win32:LIBS += -L$$path/lib -llibmysql
  • oci.pro文件內容下面加上如下代碼。
path = C:/app/Administrator/product/11.2.0/client_1
INCLUDEPATH += $$path/oci/include
win32:LIBS += -L$$path/oci/lib/msvc -loci
  • psql.pro文件內容下面加上如下代碼。
path = "C:/Program Files/PostgreSQL/13"
INCLUDEPATH += $$path/include
win32:LIBS += -L$$path/lib -llibpq
  • 以上寫法同時支持mingw和msvc,其他系統編譯過程也是類似。編譯完成後默認會在你當前源碼所在盤符的根目錄下,會出現plugins目錄,裏面sqldrivers目錄下就是對應編譯生成好的插件動態庫。
  • 默認oracle的插件驅動代碼是按照oracle12的函數寫的,如果鏈接的是oracle11,則需要改動兩行代碼才能編譯成功。打開qsql_oci.cpp文件大概在1559行代碼左右,有個OCIBindByPos2函數改成OCIBindByPos,下面還有一行bindColumn.lengths改成(ub2*)bindColumn.lengths。
  1. 關於Qt數據庫開發的一些冷知識。
  • Qt即支持庫的形式直接和數據庫通信,也支持ODBC數據源的形式和各種數據庫通信,這樣就涵蓋了所有的情況。
  • Qt數據庫程序打包發佈,所有前提:注意區分32/64位,你的程序是32位的就必須帶上32位的庫,64位的必須帶上64位的庫,這點Qt的庫也是這個要求。mysql發佈最簡單,帶上一個mysql的動態庫文件就行(windows上的是libmysql.dll),非常簡單。sqlserver不用帶,因爲是微軟的親兒子,一般操作系統自帶。postgres需要帶上libpq.dll、libintl-8.dll、libiconv-2.dll、libeay32.dll、ssleay32.dll這幾個文件就行。oracle需要帶上oci.dll、oraociei11.dll(這個文件很大有130MB+),如果不行建議直接安裝個oracle client客戶端軟件,然後對應bin目錄設置到環境變量就好。
  • 打包發佈後測試下來,發現32位的程序也可以正常連接64位的mysql,64位的程序也可以正常連接32位的mysql,因此判斷只要和程序的庫的位數一致就行(編譯的時候也是這個規則,32位的Qt程序編譯數據庫插件也要用32位的數據庫鏈接庫。),不需要和具體的數據庫的位數一致,測試過mysql、sqlserver、postgresql數據庫都是類似規則。
  • 大量測試對比下來,通過odbc數據源的方式和直連數據庫的方式批量插入大量數據記錄,直連方式速度更快,約5%左右,所以建議儘量採用此方式,是在沒有此方式的環境才採用odbc數據源的方式,Qt默認自帶odbc數據庫插件。
  • 不同數據庫在執行sql腳本的時候,會自動將表名或者字段名轉成大寫或小寫,mysql會將表名轉成小寫、postgresql會將表名和字段名轉成小寫、oracle會將表名和字段名轉成大寫。這就導致使用QSqlTableModel調用setTable設置數據庫表名的時候,一定要和數據庫中的表名一致,區分大小寫,所以就是在對postgresql和oracle數據庫的時候一定要注意,本人就是在這裏卡了很久,差點要把這巨大的屎盆扣在Qt的BUG上。
void DbHelper::bindTable(const QString &dbType, QSqlTableModel *model, const QString &table)
{
    //postgresql全部小寫,oracle全部大寫,這兩個數據庫嚴格區分表名字段名的大小寫臥槽
    QString flag = dbType.toUpper();
    if (flag == "POSTGRESQL") {
        model->setTable(table.toLower());
    } else if (flag == "ORACLE") {
        model->setTable(table.toUpper());
    } else {
        model->setTable(table);
    }
}
  • Qt支持不指定數據庫名打開數據庫,因爲有時候是要在連接數據庫服務器後,執行sql語句創建數據庫。數據庫都還沒存在怎麼連接呢,測試發現sqlite、mysql、sqlserver、postgresql都支持這個特性。在刪除和創建數據庫的前提是該數據庫沒有被其他程序佔用,比如其他程序已經打開了該數據庫則會執行失敗。這裏我就折磨過很多次,爲什麼執行失敗呢?後面發現第三方數據庫工具已經打開了該數據庫,把工具關掉就ok了。
QSqlDatabase database = QSqlDatabase::addDatabase("QMYSQL");
//database.setDatabaseName("dbtool");
database.setHostName("127.0.0.1");
database.setPort(3306);
database.setUserName("root");
database.setPassword("root");

if (database.open()) {
    QSqlQuery query(database);
    qDebug() << "刪除數據庫" << query.exec("drop database dbtool");
    qDebug() << "創建數據庫" << query.exec("create database dbtool");
    if (query.exec("select * from userinfo")) {
        while (query.next()) {
            qDebug() << "查詢數據庫" << query.value(0);
        }
    }
} else {
     qDebug() << "打開數據庫" << database.lastError().text();
}
  • 用QSqlQueryModel+QTableView顯示數據,int類型的數據,如果超過100萬,會變成科學計數顯示,這就很惱火了,肯定不是自己想要的結果。找遍網絡搜索,終於找到一個同樣問題的哥們,需要對這一列加個空的委託就行。後面發現空委託也不行,超過1000萬條又屌樣了,需要終極大法重載數據模型顯示。
ui->tableView->setItemDelegateForColumn(0, new QItemDelegate);

//下面是終極大法
QVariant SqlQueryModel::data(const QModelIndex &index, int role) const
{
    QVariant value = QSqlQueryModel::data(index, role);
    //超過100萬的數值會被科學計數顯示需要這裏轉成字符串顯示
    if (role == Qt::DisplayRole) {
        int result = value.toInt();
        if (result >= 1000000) {
            value = QString::number(result);
        }
    }
    return value
}
  • mysql數據庫有多種數據庫引擎,其中MyIsam不支持數據庫事務,默認一般是這個引擎,所以當你使用Qt中的transaction方法後commit提交時候,會發現不成功,其實事實上又是成功的,去數據庫裏面查看對應的結果又是正確的。有兩個辦法,第一就是將數據庫引擎改成InnoDB,第二就是在提交後做個錯誤判斷 if (database.commit() || !database.lastError().isValid()) ,錯誤不可用也說明是成功的。
  • 如果採用odbc數據源通信,則只需設置數據庫名稱setDatabaseName、設置用戶名稱setUserName、設置用戶密碼setPassword這三個參數即可,因爲數據源配置的時候就已經設置好對應的主機地址和端口以及關聯的數據庫名稱,所以在用odbc數據源通信的時候只需要再次驗證用戶信息即可。這裏特別要注意的是setDatabaseName設置數據庫名稱要填寫數據源配置的名稱。
  • 經過大量的對比測試,包括插入、刪除、批量、查詢、分頁等操作,千萬量級數據,在Qt數據庫部分響應速度這塊,友好度排名依次是 sqlite > postgresql > oracle > mysql > odbc 。千萬量級以上是 postgresql > oracle > mysql > sqlite > odbc 。億級別以上是 oracle > postgresql > 其他。以上測試均建立在初學者水平基礎上,至於分庫分表、聯合查詢、緩存、內存數據庫等各種高級知識點沒用上。
  • mysql主要有兩個版本,mysql5.7和mysql8,官方說是8比5要快很多,個人測試下來,5.7比8要快很多,無論是查詢,還是批量插入數據,不知道爲何,網上搜索的也是這個結果(https://www.coder4.com/archives/7596),大家都說8慢了很多。
  • mysql有個分支叫mariadb,比mysql更純正,據說各方面都吊打mysql(https://blog.csdn.net/x275920/article/details/123847792),個人對比測試下來也是確實批量插入和查詢性能要好不少,並且完全兼容mysql,甚至庫文件直接重命名也可以直接使用,比如將libmariadb.dll改成libmysql.dll可以直接使用,而且體積還小了八倍,這個好,發佈的時候又少了好幾兆。
  • 如果是Qt+mysql程序,發佈的時候帶的庫版本要和插件對應數據庫版本一致,否則可能沒有數據庫事務特性,database.driver()->hasFeature(QSqlDriver::Transactions)爲假。
  • QSqlTableModel封裝的非常好,並不會一次性加載所有數據,而是隨着滾動條的拉動加載需要的數據,測試一億條的表,速度非常快,和幾千條的錶速度一樣。
  • 在連接網絡數據庫的時候,如果你本地網絡設置了代理,比如使用了代理上github等網站,就會發現Qt的數據庫程序連不上,你需要設置下不使用本地代理設置 QNetworkProxyFactory::setUseSystemConfiguration(false) 。這個地方如果不仔細會找問題找到你懷疑人生。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章