文章目錄
- 前言
- 一、QSettings:輕量級數據持久化方案
- 1.1 QSettings 主要特點
- 1.2 QSettings 常用函數整理
- 二、數據庫
- 2.1 連接SQLite數據庫
- 2.2 建表
- 2.3 增刪改
- 三、網絡編程
- 3.1 網絡分層
- 3.2 IP地址
- 3.3 端口號
- 3.4 基于TCP的Socket通信
- 3.4 相關接口
- 3.4.1核心類
- 3.4.2 通信原理圖
- 3.4.3 項目配置
- 3.4.4 常用函數與信號
- 3.4.4.1 QTcpServer (服務器端)
- 3.4.5 QTcpSocket (客戶端和服務器端通信對象)
- 3.4.5.1 QIODevice (所有 IO 設備基類)
- 3.4.5.2 數據讀寫方式
- 3.4.5.3 QByteArray
- 3.4.5.4 QTextStream
- 3.5 代碼示例
- 四、QT中的OpenCV
- 4.1 OpenCV簡介
- 4.2 環境搭建
- 4.3 人臉檢測
- 4.4 代碼示例
- 五、Qt程序打包
- 5.1 設置應用程序圖標
- 5.2 Debug版本與Release版本:構建應用程序的兩種模式
- 5.2 打包
- 最終章-項目演練
- 項目要求
- 實現功能
- 項目演示
- 結語
前言
在Qt基礎知識的扎實積累后,我們今天的重點將轉向Qt應用程序中至關重要的一環——數據持久化。高效且安全地存儲數據是任何復雜應用不可或缺的基礎。我們將深入探討Qt提供的數據存儲機制,從簡單的文本文件到結構化的二進制文件,再到強大的數據庫集成,旨在為您構建穩定、可擴展的Qt應用程序奠定堅實基礎。
一、QSettings:輕量級數據持久化方案
數據持久化 是指將內存中的數據模型轉換為存儲模型,以及將存儲模型轉換為內存中的數據模型的統稱。數據庫是一種常見的數據持久化方式,但對于嵌入式系統等資源受限的環境,即使是 SQLite 這樣的輕量級數據庫也可能顯得“重”。
QSettings 是 Qt 框架提供的一種比數據庫更輕量級的數據持久化方式,特別適用于存儲應用程序的配置信息、用戶偏好設置等小型數據。
1.1 QSettings 主要特點
輕量級: 無需復雜的數據庫管理系統,直接讀寫配置文件。
跨平臺: QSettings 自動處理不同操作系統下配置文件的存儲位置和格式(如 Windows 注冊表、macOS Plist 文件、Unix/Linux INI 文件等)。
簡單易用: 提供直觀的 API 進行鍵值對的讀寫。
1.2 QSettings 常用函數整理
構造函數
QSettings::QSettings(const QString & fileName, Format format, QObject * parent = 0)
參數1 fileName:存儲文件的名稱。對于INI格式,這是文件的實際名稱。對于其他格式(如Windows注冊表),QSettings 會根據應用程序和組織名稱自動確定路徑。默認為構建目錄下的一個文件。
參數2 format: 存儲格式。QSettings支持多種格式,如 QSettings::IniFormat (INI文件)、QSettings::NativeFormat (操作系統原生格式,如注冊表) 等。
參數3 parent:父對象。
設置INI文件編碼
void QSettings::setIniCodec(const char * codecName)
用途: 建議在使用INI文件格式時調用此函數,將編碼設置為 UTF-8,以避免亂碼問題。
參數 codecName: 編碼字符串,如 “UTF-8”。
數據寫入函數
beginWriteArray:以數組方式存儲(相同類型數據建議使用)
void QSettings::beginWriteArray(const QString & prefix)
用途: 當您有一組相同類型的數據需要存儲時(例如,一系列窗口位置,或一組文件路徑),beginWriteArray 提供了更結構化的方式。它會將數據存儲為數組形式。
參數 prefix: 數組的名稱。
beginGroup:以組方式存儲(不同類型數據建議使用,相同類型也可以但性能不如數組方式)
void QSettings::beginGroup(const QString & prefix)
用途: 用于組織不同類型的數據,或者將相關的鍵值對分組。這有助于保持配置文件的整潔和可讀性。
參數 prefix: 組的名稱。
setValue:在組或數組中添加鍵值對
void QSettings::setValue(const QString & key, const QVariant & value)
用途: 這是實際寫入數據的函數。它將一個鍵 (key) 與一個值 (value) 關聯起來。
參數1 key: 數據的鍵名。
參數2 value: 數據的值。QVariant 類型允許存儲多種數據類型(如 int, QString, bool 等)。
結束存儲函數
endArray:結束數組的存儲
void QSettings::endArray()
用途: 匹配 beginWriteArray,標志著當前數組寫入的結束。
endGroup:結束組的存儲
void QSettings::endGroup()
用途: 匹配 beginGroup,標志著當前組寫入的結束。
數據讀取函數
value:根據鍵獲得值
QVariant QSettings::value(const QString & key, const QVariant & defaultValue = QVariant()) const
用途: 從配置文件中讀取與指定鍵關聯的值。
參數1 key: 要讀取數據的鍵名。
參數2 defaultValue: 如果指定的鍵不存在,則返回此默認值。這可以避免讀取失敗導致程序崩潰。
返回值: 返回一個 QVariant 對象,您需要將其轉換為所需的數據類型(例如,value(“myKey”).toInt() 或 value(“anotherKey”).toString())。
代碼示例
代碼包
二、數據庫
Qt 提供了強大的機制來操作各種常見的數據庫系統。
本次課程重點: 使用 SQLite 數據庫。
原因: Qt 內置支持 SQLite,無需額外安裝或配置。
Qt 項目配置:
在使用數據庫功能之前,必須在您的 Qt 項目的 .pro 文件中添加 sql 模塊:
QT += sql
主要數據庫相關類:
QSqlDatabase: 數據庫連接類。
負責建立、管理和斷開與數據庫的連接。
QSqlError: 數據庫錯誤信息類。
用于獲取和解析數據庫操作過程中可能出現的錯誤信息。
QSqlQuery: 數據庫操作類。
用于執行 SQL 查詢語句(如 SELECT, INSERT, UPDATE, DELETE 等)。
Qt常見數據庫:
數據庫類型 | 驅動名 | 特點 |
---|---|---|
SQLite | QSQLITE | 輕量級、嵌入式、文件型數據庫。非常適合桌面應用、移動應用、嵌入式系統,無需單獨的服務器進程。Qt對其支持非常好,是許多Qt應用的首選。 |
MySQL | QMYSQL | 廣泛使用的開源關系型數據庫服務器。適用于中到大型Web應用、企業應用。 |
PostgreSQL | QPSQL | 功能強大、遵循SQL標準、開源的關系型數據庫服務器。以其高級特性、數據完整性和可靠性而聞名。 |
ODBC (通用接口) | QODBC | 開放數據庫連接 (Open Database Connectivity)。這是一個通用的API,允許應用程序通過ODBC驅動程序管理器連接到任何支持ODBC的數據庫。這意味著如果你有數據庫的ODBC驅動,Qt就可以通過QODBC連接它。通過ODBC可以連接以下數據庫:SQL Server, Oracle, Access, DB2以及其他許多兼容ODBC的數據庫。 |
Oracle | QOCI | 強大的企業級商業數據庫。Qt提供了直接的OCI (Oracle Call Interface) 驅動,提供了比ODBC更原生和高效的連接方式。 |
IBM DB2 | QDB2 | IBM的商業關系型數據庫系統。 |
Microsoft SQL Server | QODBC 或 QTDS (較少見或第三方實現) | 微軟的商業關系型數據庫服務器。通常通過QODBC連接最為常見。QTDS驅動如果存在,則可能提供更直接的連接,但不如QODBC通用。 |
2.1 連接SQLite數據庫
在Qt中連接SQLite數據庫主要涉及以下幾個步驟和關鍵函數:
- 添加數據庫驅動
首先,你需要使用QSqlDatabase::addDatabase()靜態函數來添加一個數據庫連接。對于SQLite數據庫,你需要傳入 “QSQLITE” 作為類型字符串。這個函數會返回一個QSqlDatabase對象,這個對象代表了你的數據庫連接。
相關函數:
QSqlDatabase QSqlDatabase::addDatabase(const QString & type)
參數: type - 數據庫類型字符串,對于SQLite,通常是 “QSQLITE”。
返回值: 一個 QSqlDatabase 對象,代表了數據庫連接。
示例:
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
- 設置數據庫名稱/路徑
接下來,你需要使用QSqlDatabase::setDatabaseName()函數來指定SQLite數據庫文件的路徑和名稱。
如果指定的數據庫文件不存在,SQLite會在程序嘗試打開連接時自動創建這個文件。
如果文件路徑是相對路徑,它會相對于當前應用程序的執行目錄。
成功連接后,你可以在構建目錄(通常是你的項目編譯輸出目錄)中找到生成的數據庫存儲文件。你可以使用SQLiteSpy等工具打開此文件進行查看和輔助開發。
相關函數:
void QSqlDatabase::setDatabaseName(const QString & name)
參數: name - 數據庫文件的路徑和名稱。例如,“my_database.db” 或 “C:/path/to/my_database.db”。
示例:
db.setDatabaseName("my_database.db"); // 或者 db.setDatabaseName("/path/to/my_database.db");
- 打開數據庫連接
使用QSqlDatabase::open()函數嘗試打開數據庫連接。這個函數會返回一個布爾值,指示連接是否成功。
相關函數:
bool QSqlDatabase::open()
返回值: true 表示連接成功,false 表示連接失敗。
示例:
if (!db.open()) {// 處理連接失敗的情況qDebug() << "Database connection failed!";// 可以通過 db.lastError().text() 獲取詳細錯誤信息
} else {qDebug() << "Database connected successfully!";
}
- 檢查連接狀態和處理錯誤
在打開連接之后,或者在進行其他數據庫操作時,最好檢查連接是否成功。
QSqlDatabase::isOpen() 可以檢查當前連接是否處于打開狀態。
QSqlDatabase::lastError() 返回一個 QSqlError 對象,其中包含了上一次數據庫操作的錯誤信息。
QSqlError::text() 可以從 QSqlError 對象中提取可讀的錯誤信息文本。
相關函數:
bool QSqlDatabase::isOpen() const
返回值: true 如果連接已打開,否則 false。
QSqlError QSqlDatabase::lastError() const
返回值: 一個 QSqlError 對象,包含上一次操作的錯誤信息。
QString QSqlError::text() const
返回值: 錯誤信息的文本描述。
示例:
if (!db.open()) {qDebug() << "Error: Failed to connect to database." << db.lastError().text();
}
// 在其他地方,你可以檢查連接狀態
if (db.isOpen()) {qDebug() << "Database is currently open.";
} else {qDebug() << "Database is currently closed.";
}
- 關閉數據庫連接
當不再需要數據庫連接時,使用QSqlDatabase::close()函數關閉連接。這會釋放相關的資源。
相關函數:
void QSqlDatabase::close()
示例:
db.close();
qDebug() << "Database connection closed.";
總結連接流程
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); // 添加SQLite驅動
db.setDatabaseName("your_database.db"); // 設置數據庫文件路徑
if (!db.open()) { ... } // 嘗試打開連接,并檢查結果
db.close(); // 完成操作后關閉連接
通過以上步驟,你就可以在Qt應用程序中成功連接和管理SQLite數據庫了!
2.2 建表
目標: 在數據庫中創建一個新的表。
所需類和函數:
QSqlQuery: 用于執行SQL語句的核心類。
QSqlError: 用于獲取SQL操作的錯誤信息。
核心函數回顧:
QSqlQuery::QSqlQuery() (構造函數)
作用: 創建一個QSqlQuery對象。默認情況下,它會關聯到當前的默認數據庫連接。如果你有多個數據庫連接,可以使用QSqlQuery(QSqlDatabase db)構造函數指定。
用法: QSqlQuery query; 或 QSqlQuery query(myDatabaseConnection);
bool QSqlQuery::exec(const QString & query) (執行SQL語句)
作用: 執行傳入的SQL語句。
參數: query - 一個QString類型的SQL語句。
返回值: true表示SQL語句執行成功,false表示執行失敗。
用法: bool success = query.exec(“CREATE TABLE MyTable (id INTEGER PRIMARY KEY, name TEXT)”);
QSqlError QSqlQuery::lastError() const (返回上一次操作的錯誤信息)
作用: 當exec()返回false時,可以使用此函數獲取詳細的錯誤信息,以便診斷問題。
返回值: 一個QSqlError對象,包含了錯誤類型、錯誤文本等信息。
用法: QSqlError error = query.lastError();
打開db文件查看:
在你的項目構建目錄(通常是build-yourprojectname-Desktop_Qt_x_x_x_MinGW_xx_bit或類似名稱)中,你會找到一個名為 mydatabase.db 的文件。
你可以使用任何支持SQLite的數據庫瀏覽器工具來打開這個 .db 文件,例如:
SQlitSpy 點擊下載
DB Browser for SQLite (推薦,免費且功能強大)
SQLiteStudio
各種集成開發環境(如VS Code with SQLite Viewer插件)
打開后,你將能夠看到新創建的 users 表及其定義的字段。
2.3 增刪改
在使用 QSqlQuery 進行數據庫的增刪改(以及復雜的查詢)操作時,推薦使用預處理語句配合參數綁定。這比直接拼接 SQL 字符串更加安全和高效。
核心函數介紹:
bool QSqlQuery::prepare(const QString & query)
功能:送入一個 SQL 預處理語句,以便于后續二次處理。這是使用預處理語句的第一步。
參數:
query (const QString &): 包含 SQL 語句的字符串。
特點:這個 SQL 語句中可以包含參數占位符。常見的占位符有:
命名占位符 (Named Placeholders):例如 :name, :id
位置占位符 (Positional Placeholders):例如 ? (對于大多數數據庫,包括 SQLite, PostgreSQL, MySQL)
示例:
INSERT INTO users (name, age) VALUES (?, ?)
UPDATE products SET price = :newPrice WHERE id = :productId
返回值:bool。如果預處理成功 (即 SQL 語法無誤,數據庫驅動能解析),返回 true;否則返回 false。
作用:在內部,數據庫驅動會解析這個 SQL 語句,并為后續的參數綁定和執行做好準備。
void QSqlQuery::addBindValue(const QVariant & val)
功能:綁定輸入參數到預處理語句中的占位符。
參數:
val (const QVariant &): 要綁定的值。QVariant 是 Qt 的通用數據類型,可以兼容各種常見的 Qt 數據類型(如 int, QString, double, QDateTime 等),提供了極大的靈活性。
作用:當你調用 prepare() 后,SQL 語句中的占位符需要被實際的值填充。addBindValue() 就是用來提供這些實際值的。
綁定順序/方式:
位置占位符 (?):按照你調用 addBindValue() 的順序,依次綁定到 SQL 語句中的 ? 占位符。例如,第一個 addBindValue() 對應第一個 ?,第二個對應第二個 ?。
命名占位符 (:name):在某些數據庫驅動中,addBindValue() 也可以用來綁定命名占位符,但更常見和推薦的方式是使用 QSqlQuery::bindValue(const QString & placeholder, const QVariant & val)。然而,如果數據庫驅動支持,多次調用 addBindValue() 也可以按照命名占位符在 SQL 語句中的出現順序進行綁定。
注意:每次執行預處理語句前,你需要為所有的占位符調用相應的 addBindValue() 或 bindValue()。
bool QSqlQuery::exec()
功能:執行已經預處理并綁定了參數的 SQL 語句。
參數:無。
返回值:bool。如果執行成功(例如 INSERT 成功,UPDATE 成功,即使沒有行被更新也算成功),返回 true;否則返回 false。
作用:將準備好的 SQL 語句及其綁定好的參數發送到數據庫執行。對于 INSERT, UPDATE, DELETE 語句,成功執行后可以通過 QSqlQuery::numRowsAffected() 獲取受影響的行數。對于 SELECT 語句,成功執行后可以通過 QSqlQuery::next() 遍歷查詢結果。
三、網絡編程
3.1 網絡分層
為什么要分層??由于結點之間聯系很復雜,在制定協議時,把復雜成份分解成??一些簡單的成份,再將它??們復合起來。最常用的復合方式是層次方式,即同層間可以通信、上一層可以調用下一層??而與再下一層不發生關系。各層互不影響,利于系統的開發和擴展。?
3.2 IP地址
定義: Internet Protocol (互聯網協議) 的縮寫。是網絡中每個設備的通信地址,類似于門牌號,是網絡通信的核心條件。
格式: 可以是 IPv4 或 IPv6 格式,其中 IPv4 更常用。
用途: 標識網絡中的唯一設備。
操作:
在 Windows 命令行中使用 ipconfig 命令可以查看當前計算機在局域網中的 IP 地址。
可以使用 ping 命令測試網絡連通性。
注意: Windows 默認開啟防火墻以保障網絡安全,進行局域網編程時可能需要關閉防火墻。
3.3 端口號
定義: 用于在一臺設備上唯一標識一個程序。
用途:
在知道 IP 地址或域名的情況下,如果想與該計算機上的特定程序交換數據,還必須知道該程序使用的端口號。
同一臺計算機中,不同的程序使用不同的端口號,以確保信息發送到各自對應的程序。
范圍:
一臺計算機上最多可以有 65536 個端口號(1-65535)。
重要提示: 1024 以下的端口號是預留給一些著名應用程序使用的,不建議占用,例如:
HTTP: 80
FTP: 21
SMTP: 25
POP3: 110
3.4 基于TCP的Socket通信
TCP (Transmission Control Protocol): 傳輸控制協議。
特性: 是一種基于連接的協議。
連接建立: 在正式收發數據之前,必須先與對方建立可靠的連接。這個連接建立過程需要經過“三次對話”,被稱為三次握手。
三次握手步驟:
詢問: (客戶端發送連接請求)
確定: (服務器回應并確認收到請求)
連接: (客戶端再次確認,連接正式建立)
3.4 相關接口
您提供的文本內容是對Qt網絡編程中TCP相關類(QTcpServer和QTcpSocket)及其常用接口、通信原理和讀寫方式的詳細說明。為了更好地理解和整理,我將對內容進行結構化和補充,并對關鍵點進行提煉。
3.4.1核心類
Qt 提供了兩個主要的類用于 TCP 網絡編程:
- QTcpServer:
- 作用: 基于 TCP 的服務器管理類。
- 特點: 自身不具備任何 IO (輸入/輸出) 功能,主要負責監聽客戶端連接請求。
- QTcpSocket:
- 作用: 基于 TCP 的通信連接類。
- 特點: 間接繼承自
QIODevice
,因此具備讀寫數據的功能。它是客戶端與服務器之間實際進行數據交換的載體。
3.4.2 通信原理圖
+----------------+ +----------------+
| Server | | Client |
| (QTcpServer) | | (QTcpSocket) |
+----------------+ +----------------+| || 1. 監聽端口 (listen) || ||<---------------------------------------| 2. 連接到服務器 (connectToHost)| (客戶端發起連接請求) || || 3. newConnection() 信號發出 || || 4. nextPendingConnection() || (服務器“下蛋”得到一個QTcpSocket) || |
+-------V-------+ +----------------+
| QTcpSocket | <-------------------> | QTcpSocket |
| (服務器端) | 5. 建立連接 | (客戶端) |
+---------------+ +----------------+| ||<--------------------------------------->| 6. 數據讀寫 (readAll, QTextStream, write)| (通過各自的QTcpSocket進行數據通信) |
3.4.3 項目配置
要在 Qt 項目中使用網絡功能,需要在 .pro
文件中添加網絡模塊:
QT += network
3.4.4 常用函數與信號
3.4.4.1 QTcpServer (服務器端)
- 構造函數:
QTcpServer::QTcpServer(QObject * parent = 0)
- 監聽:
bool QTcpServer::listen(const QHostAddress & address = QHostAddress::Any, quint16 port = 0)
- 功能: 開啟服務器監聽,等待客戶端連接請求。
- 參數:
address
:QHostAddress
是 IP 地址的封裝類。QHostAddress::Any
表示監聽所有可用 IP 地址上的請求。port
: 服務器端口號。0
表示隨機分配一個可用端口。
- 返回值:
true
表示監聽成功,false
表示失敗 (常見失敗原因為端口被占用)。
- 判斷是否監聽:
bool QTcpServer::isListening() const
- 關閉服務器:
void QTcpServer::close()
- 信號:
void QTcpServer::newConnection()
: 當有新客戶端連接建立時發出此信號。
- 獲取待處理連接:
QTcpSocket * QTcpServer::nextPendingConnection()
- 功能: 在
newConnection()
信號發出后調用此函數,服務器會“下蛋”生成一個QTcpSocket
對象,用于與剛剛連接的客戶端進行通信。這個QTcpSocket
對象是服務器與該客戶端通信的“綠蛋”。
- 功能: 在
3.4.5 QTcpSocket (客戶端和服務器端通信對象)
- 構造函數:
QTcpSocket::QTcpSocket(QObject * parent = 0)
- 連接到主機:
void QAbstractSocket::connectToHost(const QString & hostName, quint16 port, OpenMode openMode = ReadWrite)
- 功能: 客戶端發起連接請求到指定服務器。
- 參數:
hostName
: 服務器的 IP 地址或域名。port
: 服務器的端口號。openMode
: IO 打開模式,默認為ReadWrite
(讀寫模式)。
- 判斷 IO 流是否打開:
bool QIODevice::isOpen() const
- 獲取對方 IP 地址:
QHostAddress QAbstractSocket::peerAddress() const
- 獲取對方端口號:
quint16 QAbstractSocket::peerPort() const
- 獲取 IP 地址字符串:
QString QHostAddress::toString() const
- 注意: 某些系統可能會返回多余字符,需要自行裁剪。
- 信號:
void QAbstractSocket::connected()
: 當成功連接到服務器時發出此信號 (客戶端)。void QAbstractSocket::disconnected()
: 當連接斷開時發出此信號 (客戶端或服務器端)。
3.4.5.1 QIODevice (所有 IO 設備基類)
- 信號:
void QIODevice::readyRead()
: 當有新內容可讀時發出此信號。
- 讀取所有內容:
QByteArray QIODevice::readAll()
- 功能: 將當前可讀的所有數據讀取到一個
QByteArray
中。
- 功能: 將當前可讀的所有數據讀取到一個
3.4.5.2 數據讀寫方式
Qt 提供了兩種主要的讀寫接口,適用于不同場景:
3.4.5.3 QByteArray
- 特點:
- 使用 8 位字節作為基礎存儲單位。
- 兼容性更好: 適用于 Qt 程序與其他非 Qt 程序(如 C++ 標準庫、Java、Python 等)進行通信。
- 推薦場景: 跨語言、跨平臺或協議定義為字節流的通信。
- 讀寫:
QByteArray QIODevice::readAll()
: 讀取所有可用的字節數據。qint64 QIODevice::write(const QByteArray & data)
: 寫入字節數據。
3.4.5.4 QTextStream
- 特點:
- 使用 16 位
QChar
作為基礎存儲單位。 - 使用更方便: 封裝了文本格式化和解析功能,可以直接讀寫字符串、數字等。
- 推薦場景: 僅限于 Qt 程序之間進行文本通信,尤其是不涉及復雜二進制協議的簡單文本數據交換。
- 使用 16 位
- 構造函數:
QTextStream::QTextStream(QIODevice * device)
- 功能: 將
QTextStream
綁定到一個QIODevice
(例如QTcpSocket
) 上。
- 功能: 將
- 讀取所有文本:
QString QTextStream::readAll()
- 功能: 從關聯的
QIODevice
中一口氣讀取所有可用的文本數據。
- 功能: 從關聯的
- 其他讀寫操作: 支持
operator<<
和operator>>
進行格式化輸入輸出 (例如QTextStream << "Hello" << endl;
).
3.5 代碼示例
服務器和客戶端通訊代碼示例包
四、QT中的OpenCV
4.1 OpenCV簡介
OpenCV主要通過C++實現,Python接口是基于此開發的。
C++接口在官方文檔中更靠前。
官方文檔鏈接:官方文檔
4.2 環境搭建
-
步驟1:下載OpenCV離線包
網盤鏈接:opencv -
步驟2:解壓并拷貝
將解壓后的文件拷貝到D盤下,注意文件夾層級,避免多一層目錄。
-
步驟3:打開Windows環境變量配置。
-
步驟4:配置系統環境變量。
-
步驟5:重啟電腦。
-
步驟6:新建Qt項目并配置.pro文件
Qt項目路徑需為英文。
在.pro文件中添加以下OpenCV庫路徑:
INCLUDEPATH += D:/opencv/opencv3.4-install/install/include
INCLUDEPATH += D:/opencv/opencv3.4-install/install/include/opencv
INCLUDEPATH += D:/opencv/opencv3.4-install/install/include/opencv2
LIBS += D:/opencv/opencv3.4-install/install/x86/mingw/lib/libopencv_*.a
- 步驟7:在main.cpp中編寫測試代碼驗證環境
#include "dialog.h"
#include <QDebug>
#include <opencv2/opencv.hpp> // 引入OpenCV頭文件
using namespace cv; // 使用名字空間
int main(int argc, char *argv[])
{Mat src; // 矩陣存儲圖像,相當于ndarraysrc = imread("handsome.jpg"); // 根目錄是構建目錄if(!src.data){qDebug() << "讀取失敗!";return -1;}imshow("input", src);waitKey(0);return 0;
}
問題解決:
如果出現未響應情況,可:參考文章
4.3 人臉檢測
原理:
通過定時器獲取攝像頭采集的圖像。
使用OpenCV自帶的人臉數據模型與圖像進行比對,執行人臉檢測。
在檢測到的人臉周圍畫紅框進行標注。
QImage構造函數:
QImage(
const uchar * data, // 圖像數據
int width, // 寬度(列數)
int height, // 高度(行數)
int bytesPerLine, // 每一行的總通道數 = 寬度 * 通道數
Format format) // 圖像格式
QImage轉換為QPixmap:
QPixmap QPixmap::?fromImage(const QImage & image) [static] // 參數為要轉換的QImage圖像
4.4 代碼示例
人臉識別代碼
五、Qt程序打包
5.1 設置應用程序圖標
操作步驟如下:
第一步:準備圖標文件 (.ico 格式)
- 選擇圖片: 找到一張你喜歡的圖片作為應用程序圖標。
- 轉換格式: 借助在線網站將圖片轉換為
.ico
格式。- 推薦分辨率: 256 x 256 像素。
- 在線轉換工具:
- https://cn.office-converter.com/png-to-ico
- https://convertio.co/zh/
重磅介紹本地轉換工具:
ImageMagick
使用命令行cmd打開
運行指令:
magic xxx.png xxx.ico
該工具極其強大,還有其他很多專業作用,請參照官網ImageMagic使用指南
- 命名并放置: 將轉換后的
.ico
文件正確命名(例如icon.ico
)并放置到你的 Qt 項目的工作目錄中(通常是.pro
文件所在的目錄)。
第二步:創建資源配置文件 (.rc)
-
在 Qt Creator 中:
- 選中你的項目名稱(在左側的項目視圖中)。
- 鼠標右鍵,點擊“添加新文件”。
-
選擇文件類型:
- 在彈出的窗口中,選擇
- 在彈出的窗口中,選擇
-
命名配置文件:
- 輸入圖標配置文件的名稱(例如
icon_config.rc
)。 - 重要: 務必加上文件的擴展名
.rc
。 - 點擊“Next”。
- 輸入圖標配置文件的名稱(例如
-
完成創建:
- 在項目管理界面,直接點擊“完成”。
-
編輯 .rc 文件:
-
打開剛剛創建的
.rc
文件。 -
-
輸入以下配置參數,將
icon.ico
替換為你的圖標文件名稱:IDI_ICON1 ICON DISCARDABLE "icon.ico"
-
第三步:配置項目文件 (.pro)
- 打開 .pro 文件: 在 Qt Creator 中找到并打開你的項目
.pro
文件。
2. 添加配置項: 在 .pro
文件中,增加下面的配置項,將 icon_config.rc
替換為你的 .rc
文件名稱:
cpp //后面的參數就是rc文件的名稱 RC_FILE += test.rc
第四步:編譯運行
- 編譯項目: 在 Qt Creator 中點擊“構建”或“運行”按鈕。
- 觀察效果: 觀察編譯生成的應用程序的可執行文件圖標是否已成功設置。
總結流程圖:
5.2 Debug版本與Release版本:構建應用程序的兩種模式
在軟件開發過程中,我們通常會使用兩種主要的構建版本來編譯和打包我們的應用程序:Debug版本和Release版本。它們各自有不同的用途和特點。
1. Debug版本 (調試版本)
- 用途: 主要用于開發和調試階段。
- 特點:
- 包含開發信息: 生成的可執行文件中會包含大量的調試信息,例如符號表、源碼行號等。
- 性能較低: 由于包含額外信息且通常不做性能優化,程序運行速度相對較慢。
- 體積較大: 調試信息的加入會使生成的文件體積增大。
- 易于調試: 調試器可以利用這些信息方便地進行斷點設置、變量查看、步進執行等操作,幫助開發者定位和修復錯誤。
2. Release版本 (發布版本)
- 用途: 最終用于發布給用戶。
- 特點:
- 性能優化: 編譯器會對程序進行高度優化,例如代碼精簡、內聯函數、循環展開等,以提高運行速度和效率。
- 體積小巧: 移除了調試信息和未使用的代碼,使生成的文件體積更小。
- 不便調試: 由于經過優化和移除了調試信息,這類程序在發布后不方便被調試。如果出現問題,定位起來會更加困難。
- 用戶體驗: 運行速度快、體積小,更適合最終用戶使用。
Debug版本是開發者的工具,旨在幫助他們高效地發現和解決問題;Release版本則是面向最終用戶的產品,追求最佳的性能和用戶體驗。我們使用Release版本打包。
主題:Qt 應用程序的動態鏈接庫 (DLL) 打包
核心概念:
- 動態鏈接庫 (DLL):Windows 系統下的動態鏈接庫文件,包含可被多個應用程序共享的代碼和資源。Qt 應用程序在運行時會調用 Qt 庫中的接口,這些接口通常封裝在 DLL 文件中。
- 構建目錄:Qt 項目編譯后生成可執行文件的目錄,通常包含
debug
和release
子目錄。
在沒有 Qt 開發環境的計算機上雙擊運行 Qt 生成的 .exe
可執行文件時,通常會因為缺少必要的 Qt DLL 文件而報錯。
解決方案:補充 EXE 所需的 DLL 文件
以下是打包 Qt 應用程序,使其能在無 Qt 環境計算機上運行的步驟:
-
準備打包根目錄:
- 將 Release 模式下生成的
.exe
可執行文件單獨復制到一個新的文件夾中。這個文件夾將作為最終軟件打包的根目錄。
- 將 Release 模式下生成的
-
啟動帶 Qt 環境的命令行:
- 在 Windows 搜索框中搜索并啟動一個“帶 Qt 環境的命令行”(例如 Qt Creator 自帶的“Qt 5.xx for Desktop (MinGW / MSVC)”命令行)。
- 在 Windows 搜索框中搜索并啟動一個“帶 Qt 環境的命令行”(例如 Qt Creator 自帶的“Qt 5.xx for Desktop (MinGW / MSVC)”命令行)。
-
切換命令行目錄:
- 使用命令行命令
cd
切換到您在步驟 1 中創建的軟件打包根目錄。- 常用命令行命令提示:
cd <子目錄>
:進入指定子目錄。cd ..
:返回上級目錄。dir
:顯示當前目錄內容。<盤符>:
(例如D:
):切換到指定盤符。
- 常用命令行命令提示:
- 使用命令行命令
-
執行 DLL 提取命令:
- 在命令行中,于軟件打包根目錄執行以下命令,提取所需的 DLL 文件:
windeployqt 可執行文件名稱.exe
- 注意: 將
可執行文件名稱.exe
替換為您的實際.exe
文件名。
- 注意: 將
- 在命令行中,于軟件打包根目錄執行以下命令,提取所需的 DLL 文件:
-
驗證:
- 命令執行完成后,回到軟件打包根目錄,再次雙擊運行您的
.exe
文件,應該可以正常運行。
- 命令執行完成后,回到軟件打包根目錄,再次雙擊運行您的
-
重要提示:
- 最終的“軟件根目錄”(即打包后的文件夾)在功能上相當于開發階段的“工作目錄”和“構建目錄”的結合體,包含了運行應用程序所需的所有文件。
總結流程圖:
5.2 打包
打包軟件:Inno Setup
使用方法:使用方法博文
最終章-項目演練
恭喜所有的小伙伴們!在經歷了這么多篇博文的學習之后,我們終于迎來了Qt學習之旅的又一個里程碑——筆者的qt博文系列的結尾。這并非真正的終點,更像是一個小憩,讓我們得以回顧和鞏固所學。從最初的界面搭建到復雜的信號槽機制,從數據處理到文件操作,我們一同探索了Qt的奇妙世界。它強大的功能和優雅的C++接口,為我們的開發插上了翅膀。當然,Qt的廣闊天地遠不止于此,它還有無數的寶藏等待我們去發掘。希望這次旅程能激發大家對Qt更深層次學習的興趣,未來繼續在Qt的道路上,創造出更多精彩的應用。那么最后的最后,我們一起來自己動手做一個小項目吧!
項目要求
編寫一個聊天室
實現功能
1. 實現注冊登錄
2. 實現聊天
3. 增加歷史聊天查詢功能
4. 美化界面
5. 打包成安裝包
項目演示
[演示視頻](【基于Qt的聊天室項目】 https://www.bilibili.com/video/BV1B4j3zHEoG/?share_source=copy_web&vd_source=28f8f5f13e40ab01eafa4c84779eb390)
結語
在Qt的廣闊天地中,數據持久化、網絡通信和圖像處理是構建現代、復雜應用程序不可或缺的三大支柱。本系列文章從輕量級的QSettings到強大的數據庫集成,從TCP/IP網絡基礎到QTcpServer/QTcpSocket的實戰運用,再到Qt與OpenCV的無縫結合,最終以應用程序打包和項目實戰為收尾,希望能為您打開Qt高級應用開發的大門。盡管我們探討了諸多核心概念和技術細節,Qt的潛力遠不止于此。愿您能將這些知識融會貫通,持續探索,在Qt的道路上創作出更多創新、高效且用戶友好的軟件。未來的開發之路充滿挑戰與機遇,愿我們攜手共進,在Qt的精彩世界中不斷成長!