欧美vvv,亚洲第一成人在线,亚洲成人欧美日韩在线观看,日本猛少妇猛色XXXXX猛叫

新聞資訊

    Qt是什么?Qt簡介(非常全面)

    Qt(官方發音 [kju:t],音同 cute)是一個跨平臺的 C++ 開發庫,主要用來開發圖形用戶界面(Graphical User Interface,GUI)程序,當然也可以開發不帶界面的命令行(Command User Interface,CUI)程序。

    Qt 還存在 Python、Ruby、Perl 等腳本語言的綁定, 也就是說可以使用腳本語言開發基于 Qt 的程序。開源社區就是這樣,好東西就會被派生擴展,到處使用, 越來越壯大。

    Qt 支持的操作系統有很多,例如通用操作系統 Windows、Linux、Unix,智能手機系統 Android、iOS、WinPhone, 嵌入式系統 QNX、VxWorks 等等。

    Qt 可以做什么?

    Qt 雖然經常被當做一個 GUI 庫,用來開發圖形界面應用程序,但這并不是 Qt 的全部;Qt 除了可以繪制漂亮的界面(包括控件、布局、交互),還包含很多其它功能,比如多線程、訪問數據庫、圖像處理、音頻視頻處理、網絡通信、文件操作等,這些 Qt 都已經內置了。

    Qt 是應用程序開發的一站式解決方案,有了 Qt,你就可以高枕無憂了!Qt 本身包含的模塊也日益豐富, 一直有新模塊和第三方模塊加入進來。

    大部分應用程序都可以使用 Qt 實現,除了與計算機底層結合特別緊密的,例如驅動開發,它直接使用硬件提供的編程接口,而不能使用操作系統自帶的函數庫。

    1997年,Qt 被用來開發 Linux 桌面環境 KDE,大獲成功,使 Qt 成為 Linux 環境下開發 C++ GUI 程序的事實標準。

    下面的程序都使用 Qt 開發:WPS、YY語音、Skype、豆瓣電臺、蝦米音樂、淘寶助理、千牛、暴雪的戰網客戶端、VirtualBox、Opera、咪咕音樂、Google地圖、Adobe Photoshop Album 等。

    Linux 也是嵌入式的主力軍,廣泛應用于消費類電子、工業控制、軍工電子、電信/網絡/通訊、航空航天、汽車電子、醫療設備、儀器儀表等相關行業。

    Qt 雖然也支持手機操作系統,但是由于 Android 本身已經有 Java 和 Kotlin,iOS 本身已經有 Objective-C 和 Swift,所以 Qt 在移動端的市場份額幾乎可以忽略。

    總起來說,Qt 主要用于桌面程序開發和嵌入式開發。

    Qt 和智能手機

    Qt 目前支持主流的 Android、iOS、WinPhone 等智能機操作系統。MeeGo 是基于 Qt 開發的操作系統,由于被諾基亞拋棄了, 只剩一代絕版諾基亞 N9 手機。

    諾基亞手機部門出售給微軟之后,大部分諾基亞手機系統開發人員都被遣散了。

    原來諾基亞的一部分人成立新的 Jolla(卓藍)公司,發布了 MeeGo 的衍生版智能手機系統 Sailfish(旗魚),相應的手機和平板也發布開賣了。

    另一撥人投靠了 Tizen(泰澤),Tizen 是英特爾和三星力推的智能手機系統,該系統整合了 Limo 和 MeeGo,因為 MeeGo 系統被諾基亞拋棄,英特爾其實是被出賣了,所以只能聯合三星重造智能手機系統 Tizen。

    目前基于 Tizen 的首款手機三星 Z1 在印度上市了。在 Tizen 陣營,國內有中興、百度涉及了。Qt 開源項目里也有 Qt for Tizen 版本,有興趣的可以去搜搜。

    Qt 公司有專門針對移動開發的商業版本,20 歐元或 25 美元一個月。不做商業可以無視這個,用開源版本也是可以開發如 Android、iOS、WinPhone 應用的。

    本教程關注的是傳統桌面操作系統開發的,移動開發可以參考 Qt 官方的文檔。

    Qt 的辛酸史

    說到 Qt 的發展史,那真是一波三折,幾經賣身。

    Qt 最早是 1991 年由挪威的 Eirik Chambe-Eng 和 Haavard Nord 開發的, 他們隨后于 1994 年 3 月 4 號正式成立奇趣科技公司(Trolltech)。Qt 原本是商業授權的跨平臺開發庫, 在 2000 年奇趣科技公司為開源社區發布了遵循 GPL(GNU General Public License)許可證的開源版本。

    在 2008 年,諾基亞公司收購了奇趣科技公司,并增加了 LGPL(GNU Lesser General Public License)的授權模式。諾基亞聯合英特爾利用 Qt 開發了全新的智能手機系統 MeeGo,可惜遭遇了微軟木馬屠城,諾基亞被迫放棄了 MeeGo, 而 Qt 商業授權業務也于 2011 年 3 月出售給了芬蘭 IT 服務公司 Digia。

    當然好消息是 Digia 于 2014 年 9 月宣布成立 Qt Company 全資子公司,獨立運營 Qt 商業授權業務。目前 Qt 公司大力推廣移動平臺開發和商業應用, 總的來說 Qt 歷經曲折,現在算是步入正軌了。

    經過 20 多年的發展,Qt 已經成為最優秀的跨平臺開發框架之一,在各行各業的項目開發中得到廣泛應用。許多大型軟件都是用 Qt 開發的,如 Autodesk Maya、Google Earth、Skype、WPS Office等。

    永遠不要忽視微軟帝國的威脅,作為軟件業的一代霸主,任何人都不要天真地試圖和它做朋友,因為霸主不可能有朋友。微軟的木馬屠城是所有諾基亞人和芬蘭人的痛,希望讀者們都記牢這條。

    Qt 和 KDE

    之前提到 Qt 原本是商業授權軟件,是怎么開源的呢?這就涉及 Qt 和 KDE 的糾葛了。

    KDE 是 Linux 操作系統的桌面環境,與 GNOME 桌面是類似的,作為開源桌面它們競爭的情況更為多見,有興趣的讀者請猛擊《Linux桌面環境》了解更多。

    KDE 是采用 GPL 許可證發布的開源軟件,而最初 Qt 是商業授權的,存在商業侵權風險,GNOME 則是基于開源 GTK 庫的,沒有什么商業風險,這一度是 GNOME 優越于 KDE 的特性。

    由于 Qt 的商業授權,KDE 社區一度混亂糾結,與此同時 GNOME 則如火如荼發展起來了。 KDE 畢竟算是親兒子,被另一波人欺負,奇趣科技公司當然看不下去了,最后是奇趣科技公司為了贏得開發者的支持,為 Qt 增加了 GPL 的開源授權, 對于開源社區而言,遵循 GPL 使用 Qt 就不需要付費,這為 KDE 解決了燃眉之急。

    之后 KDE 桌面和 GNOME 都發展壯大起來,都做得越來越好了。

    GPL 和 LGPL

    除了商業授權,目前 Qt 的開源授權有兩種,一種是 GPL 授權,另一種是 LGPL 授權(諾基亞收購后新增)。

    對這兩種開源授權,簡單來說,使用 GPL 版本的軟件一定還是 GPL 的開源軟件,無論是使用了 Qt 的程序代碼還是修改了 Qt 庫代碼,都必須按照 GPL 來發布,這是 GPL 的傳染性。

    GPL 是什么都要開源,這對商業軟件應用是不利的,所以諾基亞增加了 LGPL 授權 (第一個 L 可以叫 Lesser 寬松版或 Library 開發庫版)。使用 LGPL 授權就可以利用 Qt 官方動態鏈接庫,而不必開放商業代碼。只要不修改和定制 Qt 庫,僅使用 Qt 官方發布的動態鏈接庫就可以不開源,這是商業友好的授權模式。

    其實只要不是做商業,就不太需要關注用什么授權,以 GPL 授權發布程序代碼就可以了。

    世界上的開源協議有很多,最后請認準 Qt 官方網站(有時候訪問速度很慢甚至不能訪問,讀者請自備梯子),可以查閱文檔或者瀏覽資訊:https://www.qt.io/

    Qt和其它GUI庫的對比

    世界上的 GUI 庫多如牛毛,有的跨平臺,有的專屬于某個操作系統;有的只有 UI 功能,有的還融合了網絡通信、多媒體處理、數據庫訪問等底層功能。

    Windows 下的 GUI 庫

    Windows 下的 GUI 解決方案比較多:

    基于 C++ 的有 Qt、MFC、WTL、wxWidgets、DirectUI、Htmlayout;

    基于 C# 的有 WinForm、WPF;

    基于 Java 的有 AWT、Swing;

    基于 Pascal 的 有Delphi;

    基于Go語言的有 walk 和 electron;

    還有國內初露頭角的 aardio;

    Visual Basic 曾經很流行,現在逐漸失去了色彩;

    如果你有 Web 開發經驗,也可以基于 Webkit 或 Chromium 將網頁轉換為桌面程序。

    沒有哪一種方案能夠獨霸 Windows,使用比較多的編程語言是 C++、C#、Java。

    用 Qt 來開發 Windows 桌面程序有以下優點:

    簡單易學:Qt 封裝的很好,幾行代碼就可以開發出一個簡單的客戶端,不需要了解 Windows API。

    資料豐富:資料豐富能夠成倍降低學習成本,否則你只能去看源碼,關于 DirectUI、Htmlayout、aardio 的資料就很少。

    漂亮的界面:Qt 很容易做出漂亮的界面和炫酷的動畫,而 MFC、WTL、wxWidgets 比較麻煩。

    獨立安裝:Qt 程序最終會編譯為本地代碼,不需要其他庫的支撐,而 Java 要安裝虛擬機,C# 要安裝 .NET Framework。

    跨平臺:如果你的程序需要運行在多個平臺下,同時又希望降低開發成本,Qt 幾乎是必備的。

    Qt 和 MFC

    讀者經常將 MFC 和 Qt 進行對比,MFC 只能應用在 Windows 平臺,而 Qt 是跨平臺的,一次編寫,到處運行。

    另外,Qt 已經封裝了底層細節,學習 Qt 將會非常簡單;而 MFC 只是給 Windows API 加了一層包裝,不了解 Windows API 也學不好 MFC,大家普遍反映 MFC 難學。

    我們不能簡單地說 Qt 好還是 MFC 好,兩者都有用武之地;但是初學者學習 Qt 會比較簡單,不用應付那些煩人的 Windows API,很快就能開發出帶有漂亮界面的應用程序。

    Linux 下的 GUI 庫

    Linux 下常用的 GUI 庫有基于 C++ 的 Qt、GTK+、wxWidgets,以及基于 Java 的 AWT 和 Swing。其中最著名的就是 Qt 和 GTK+:KDE 桌面系統已經將 Qt 作為默認的 GUI 庫,Gnome 桌面系統也將 GTK+ 作為默認的 GUI 庫。

    相比 GTK+,Qt 的功能更加強大,更新也很快,比較受人們追捧。

    學習QML還是C++?

    Qt4 時代的主流就是傳統部件(或叫控件)編程,所用的語言一般是 C++。 Qt5 誕生之時,正是手機移動設備蓬勃發展的時候,而傳統的 C++ 部件編寫的界面對手機應用程序非常方便,比如手機屏幕顯示隨意翻轉, 這在傳統桌面程序里基本遇不到,誰會將 22 寸顯示器翻過來轉過去呢。

    為了適應手機移動應用開發, Qt5 將 QML 腳本編程提到與傳統 C++ 部件編程相同的高度,力推 QML 界面編程,當然 QML 主要用于手機移動應用程序。 QML 包含大量使用手機移動設備的功能模塊,比如基本部件(QtQuick 模塊)、GPS 定位、渲染特效、藍牙、NFC、WebkKit 等等。

    QML 類似于網頁設計的 HTML,是一種標記語言,我們可以借助 CSS 對它進行美化,也可以借助 JavaScript 進行交互。有 Web 開發經驗的讀者學習 QML 將非常輕松。

    使用 QML 開發界面主要有以下幾個優點:

    QML 非常靈活,可以做出非常炫酷的效果,例如 QQ、360、迅雷等都不在話下。

    QML 是標記語言,見名知意,非常容易編寫和閱讀,大大提高了開發和維護效率。

    QML 界面簡潔大氣,有很多動畫,適合移動端。

    不同平臺下的 QML 使用相同的渲染機制,界面效果一致,不會隨操作系統的不同而變化。

    既然 QML 有這么多優點,我們是不是可以不學 C++,直接學習 QML 呢?

    非也!QML 只能用來進行界面設計和人機交互,也就是只能勝任 UI 部分,在底層仍然需要調用 C++ 編寫的組件來完善功能,比如訪問數據庫、網絡通信、多線程多進程、文件讀寫、圖像處理、音頻視頻處理等都離不開 C++。

    另外,現階段新生的 QML 還不如傳統的 C++ 部件編程那樣擁有豐富的開發組件,尤其缺乏復雜的企業級應用程序所必須的樹等控件。這就決定了至少現階段,真正大型的桌面程序仍然只能選擇以 C++ 為主、QML 為輔的開發模式。

    相信大部分讀者都沒有 Web 開發經驗,學習 QML 成本還是比較高的,不但要習慣 QML 這種標記性語言,還要學習 CSS 和 JavaScript。

    總的來說,C++ 對于 Qt 是不可或缺的,而 QML 只是一個加分項。

    本教程只講解 C++ 部件編程

    C++依舊是 Qt 的主要編程語言,Qt 5 也并沒有忽略它,Qt 5 添加了很多新的 C++ API,而且會持續更新。引入 QML 只是 Qt 5 提供的另外一種選擇,并不是讓它成為唯一的選擇。

    C++ 是 Qt 的基礎,無論如何都要掌握,本教程也只講解傳統的 C++ 部件編程,不講解 QML。

    Qt下載(多種下載通道+所有版本)

    Qt 體積很大,有 1GB~3GB,官方下載通道非常慢,相信很多讀者會崩潰,所以建議大家使用國內的鏡像網站(較快),或者使用迅雷下載(很快)。

    作為 Qt 下載教程,本文會同時講解以上三種下載方式。

    Qt 官方下載(非常慢)

    Qt 官網有一個專門的資源下載網站,所有的開發環境和相關工具都可以從這里下載,具體地址是:http://download.qt.io/

    目錄

    說明

    archive

    各種 Qt 開發工具安裝包,新舊都有(可以下載 Qt 開發環境和源代碼)。

    community_releases

    社區定制的 Qt 庫,Tizen 版 Qt 以及 Qt 附加源碼包。

    development_releases

    開發版,有新的和舊的不穩定版本,在 Qt 開發過程中的非正式版本。

    learning

    有學習 Qt 的文檔教程和示范視頻。

    ministro

    迷你版,目前是針對 Android 的版本。

    official_releases

    正式發布版,是與開發版相對的穩定版 Qt 庫和開發工具(可以下載Qt開發環境和源代碼)。

    online

    Qt 在線安裝源。

    snapshots

    預覽版,最新的開發測試中的 Qt 庫和開發工具。

    archive 和 official_releases 兩個目錄都有最新的 Qt 開發環境安裝包,我們以 archive 目錄里的內容為例來說明。點擊進入 archive 目錄,會看到四個子目錄:

    目錄

    說明

    vsaddin

    這是 Qt 針對 Visual Studio 集成的插件,本教程基本不使用 Visual Studio ,所以不需要插件。

    qtcreator

    這是 Qt 官方的集成開發工具,但是 qtcreator 本身是個空殼,它沒有編譯套件和 Qt 開發庫。 除了老版本的 Qt 4 需要手動下載 qtcreator、編譯套件、Qt 開發庫進行搭配之外,一般用不到。對于我們教程壓根不需要下載它,因為 Qt 5 有專門的大安裝包,里面包含開發需要的東西,并且能自動配置好。

    qt

    這是 Qt 開發環境的下載目錄,我們剛說的 Qt 5 的大安裝包就在這里面。

    online_installers

    在線安裝器,國內用戶不建議使用,在線安裝是龜速,還經常斷線。我們教程采用的全部是離線的大安裝包。

    我們再進入 qt 子目錄 ,看到如下列表:

    圖3:進入 qt 子目錄

    上圖沒有列完整,這個 qt 目錄包含了所有的 Qt 版本,從 1.0 到目前的 5.12 。

    由于 Qt 5.9 是一個長期技術支持版本(Long Term Support,LTS),在未來幾年里都將有更新支持,因此,本教程以 Qt 5.9 LTS 版本為例進行講解,并且所有實例程序均使用 Qt 5.9 編譯測試通過。

    Qt 的上一個 LTS 版本是 5.6,它其實已經超出支持期了。

    進入 5.9 目錄,會看到各種子版本:

    圖4:Qt 5.9 的各個子版本

    這里解釋一下 Qt 的版本號,比如 5.9.8 是完整的 Qt 版本號,第一個數字 5 是大版本號(major),第二個數字 9 是小版本號(minor),第三個數字 8 是補丁號(patch)。 只要前面兩個數字相同,Qt 的特性就是一致的,最后的數字是對該版本的補丁更新。也就是說本教程對 5.9.* 系列的 Qt 都是通用的,下載 5.9.* 任意一個版本都可以,這里我們以下載 5.9.0。

    點擊 5.9.0,進入子目錄:

    圖5:Qt 5.9.0 下載頁面

    根據不同的操作系統,選擇不同的安裝包即可,不用管源碼包,除非你想自己編譯或者閱讀源碼。

    我們以 Windows 安裝包(qt-opensource-windows-x86-5.9.0.exe)講解一下 Qt 安裝包命名規則,其中:

    opensource 是指開源版本;

    windows 是指開發環境的操作系統;

    x86 是指 32 位系統;

    5.9.0 是 Qt 版本號。

    Qt 國內鏡像站下載(較快)

    請讀者注意圖5中最后一欄的 Details 鏈接(紅色方框圈起來的地方)。點擊 Details 鏈接可以進入詳情頁,在該頁面可以看到文件的大小、校驗和以及世界各地鏡像下載鏈接(這才是重點)。

    圖6:國內鏡像下載鏈接

    可以清楚地看到,Qt 在國內的有三個鏡像網站可以下載,點擊這些地址中的一個就可以下載,從國內鏡像網站下載速度快一些。

    國內鏡像網站

    這里給大家推薦幾個國內著名的 Qt 鏡像網站,主要是各個高校的:

    中國科學技術大學:http://mirrors.ustc.edu.cn/qtproject/

    清華大學:https://mirrors.tuna.tsinghua.edu.cn/qt/

    北京理工大學:http://mirror.bit.edu.cn/qtproject/

    中國互聯網絡信息中心:https://mirrors.cnnic.cn/qt/

    國內鏡像網站的結構和官方是類似的,我們在第一部分已經分析過了,這里不再贅述。

    迅雷下載(很快)

    將 Qt 軟件的下載地址復制到迅雷的下載框,如果迅雷官方有資源,就會自動識別,下載速度就很快了。

    如何找到 Qt 軟件的下載地址呢?以清華大學開源軟件鏡像站為例,進入 Qt 5.9.0 的下載目錄(https://mirrors.tuna.tsinghua.edu.cn/qt/archive/qt/5.9/5.9.0/),在某個鏈接處單擊鼠標右鍵,會彈出一個菜單,選擇“復制鏈接地址”,如下圖所示:

    圖7:找到 Qt 下載地址

    這樣就把 Qt 5.9.0 的下載地址(具體為 https://mirrors.tuna.tsinghua.edu.cn/qt/archive/qt/5.9/5.9.0/qt-opensource-windows-x86-5.9.0.exe)復制到了剪切板,然后再粘貼到迅雷的下載框

    點擊“立即下載”按鈕,稍等片刻,迅雷會自動匹配到資源,速度飛快。

    注意,常用的 Qt 版本一般都能匹配到資源,但是不保證每個版本都能匹配到資源,上面的例子僅對清華大學鏡像站的 Qt 5.9.0 Windows 版(https://mirrors.tuna.tsinghua.edu.cn/qt/archive/qt/5.9/5.9.0/qt-opensource-windows-x86-5.9.0.exe)有效。

    擴展閱讀

    對 Qt 版本更新感興趣的讀者請訪問 Qt wiki 網站,地址為:https://wiki.qt.io/Main

    Qt wiki 網站會顯示最新的正式版、LTS 版、正在開發中的版本等等,比主站(https://www.qt.io/)靠譜多了。Qt 主站因為商業推廣的原因,安裝包的下載步驟非常繁瑣。

    圖解Qt安裝(Windows平臺)

    本節介紹 Qt 5.9.0 在 Windows 平臺下的安裝,請提前下載好 Qt 5.9.0。不知道如何下載 Qt 的讀者請轉到:Qt下載(多種下載通道+所有版本)

    目前較高版本的 Qt 僅支持 Win7 及其以后的操作系統,不支持 Win XP;使用 Win XP 的讀者請安裝 Qt 5.5.1 之前的版本。

    Qt 占用的存儲空間很大,安裝之前建議先準備好 8GB 以上的磁盤空間。對于目前 Qt 最新版開發環境,如果不安裝源代碼包,實際占用大約 5.5GB;如果選擇安裝源碼包,大約占用 7.5GB。

    雙擊下載得到的 qt-opensource-windows-x86-5.9.0.exe 即可開始安裝。Qt 的安裝過程和普通的 Windows 軟件一樣,按照向導進行操作即可。

    關于 Qt 的安裝需要說明以下幾點。

    1) 注冊和登錄

    Qt 在安裝過程中會提示用戶進行注冊和登錄,不用理會,跳過(Skip)即可,實際開發時不需要登錄。

    圖1:Qt 安裝過程中提示用戶注冊

    2) 安裝路徑和關聯文件

    圖2:指定 Qt 安裝路徑

    Qt 允許用戶自定義安裝路徑,但是請注意,安裝路徑不能帶空格、中文字符或者其它任何特殊字符。

    另外,該界面還會詢問是否關聯特定的文件類型。如果關聯(默認是關聯的),特定后綴的文件(包括 .cpp 文件)默認使用 Qt 打開。我喜歡使用純文本編輯器(例如 Sublime Text)來打開 C++ 源文件,所以我取消了該選項,讀者根據自己的實際情況定奪。

    3) 選擇安裝組件

    Qt 安裝過程中最關鍵的一步是組件的選擇,請看下圖:

    圖3:Qt 組件

    Qt 的安裝組件分為兩部分:一部分是“Qt 5.9”分類下的,該分類包含的是真正的 Qt 開發庫組件;另一部分是“Tools”分類下的,該分類包含的是集成開發環境和編譯工具。

    “Qt 5.9”分類下的開發組件

    組件

    說明

    MinGW 5.3.0 32 bit

    編譯器模塊。MinGW 是 Minimalist GNU for Windows 的縮寫,MinGW 是 Windows 平臺上使用的 GNU 工具集導入庫的集合。是本教程使用 MinGW 編譯,所以必須安裝。

    UWP ***

    UWP 是 Windows 10 中 Universal Windows Platform 的簡稱,有不同編譯器類型的 UWP,屬于 MSVC 編譯器生成的 Qt 庫。如果不是開發 UWP 應用程序,就不需要,直接忽略。

    MSVC ***

    針對 Windows 平臺上的 MSVC 編譯器的 Qt 組件,如 msvc2015 32-bit 和 msvc2015 64-bit 等。安裝該組件需要計算機上已經安裝相應版本的 Visual Studio。如果你不使用 MSVC 編譯器進行開發,就不用安裝。本教程使用 MinGW 編譯組件,所以不用安裝 MSVC *** 組件。

    Android ***

    這是針對安卓應用開發的 Qt 庫,如果讀者有安卓開發這方面需求可以自己選擇安裝,一般情況下用不到。

    Sources

    Qt 的源代碼包,除非你想閱讀 Qt 的源碼,否則不用安裝。

    Qt ***

    Qt 的附加模塊,大部分建議安裝,這些附加模塊括號里的 TP 是指 Technology Preview ,技術預覽模塊的意思,還處在功能測試階段,不是正式版模塊;附加模塊括號里的 Deprecated 是指拋棄的舊模塊,兼容舊代碼使用的,一般用不到。這些附加模塊讀者可以選擇部分或都勾選了安裝,占用空間不大。 部分組件說明:Qt Charts 是二維圖表模塊,用于繪制柱狀圖、餅圖、曲線圖等常用二維圖表。Qt Data Visualization 是三維數據圖表模塊,用于數據的三維顯示,如散點的三維空間分布、三維曲面等。Qt Scritp(Deprecated)是腳本模塊,已被拋棄,不建議安裝。

    “Tools”分類下的開發組件

    組件

    說明

    Qt Creator 4.3.0

    這是集成開發環境,強制安裝的,以后所有的項目和代碼都在 Qt Creator 里面新建和編輯。

    Qt Creator 4.3.0 CDB Debugger surpport

    用于和 CDB 調試工具對接,默認安裝,一般用于調試 VC 編譯的 Qt 程序。

    MinGW 5.3.0

    這是開源的編譯器套件,這本教程必須用到的,需要讀者勾選安裝。

    Strawberry Perl 5.22.1.3

    用于編譯 Qt 源代碼的 Perl 開發環境,不需要安裝。如果讀者以后用到,也可以另外手動安裝,在搜索引擎搜索 Strawberry Perl 關鍵詞,去 Strawberry Perl 官網下載最新的安裝包是一樣用的。

    選擇完了組件,根據向導一步一步操作就可以了。安裝完成后,在 Windows“開始”菜單中會看到 Qt 5.9.0 程序組。

    圖4:Qt 5.9.0 所包含的程序

    程序

    說明

    Qt Creator 4.6.2 (Enterprise)

    Qt 的集成開發環境,本教程就使用它來創建和管理 Qt 項目。

    Assistant(Qt 助手)

    用來查看幫助文檔,已被集成在 Qt Creator 中。

    Designer(Qt 設計師)

    圖形界面可視化編輯工具,已被集成在 Qt Creator 中,在 Qt Creator 中編輯或創建界面文件時,就可以自動打開。

    Linguist(Qt 語言家)

    多國語言翻譯支持工具,可以用來編輯語言資源文件,在開發多語言界面的應用程序時會用到。

    Qt 5.11.1 for Desktop (MinGW 5.3.0 32bit)

    Qt 命令行工具,用來配置 Qt 開發環境(主要是設置 PATH 變量)。

    解密Qt安裝目錄的結構

    了解 Qt 安裝目錄的結構雖然不是編程必須的,但是它能練就我們的內功,讓我們對 Qt 的編程環境了如指掌。Windows 和 Linux 下 Qt 安裝目錄的結構非常相似,我們以 Windows 為例進行講解,Linux 不再贅述。

    Qt 整體目錄結構

    不同版本 Qt 的安裝目錄結構大同小異,本節我們以 Qt 5.9.0 為例來說明,如下圖所示。

    圖1:Qt 安裝目錄的結構

    為了方便描述,下文我們使用~表示 Qt 的安裝目錄。

    注意,~.9\ 和 ~\Tools\ 目錄下都有 mingw53_32 目錄(圖中我用紅色標出來了),但是兩者是有區別的:

    ~.9\mingw53_32\ 目錄包含的是 Qt 的類庫文件,例如頭文件、靜態庫、動態庫等,這些類庫文件使用 MinGW 工具集編譯而成。

    ~\Tools\mingw53_32\ 目錄包含的是 MinGW 工具集,例如編譯器 g++、鏈接器 ld、make 工具、打包工具 ar 等。

    QtCreator 是個例外,QtCreator 使用 MSVC2015 編譯生成的,所以安裝目錄里有一個 vcredist 文件夾存儲 VC 運行庫安裝文件。

    最后的 MaintenanceTool.exe ,對于離線安裝包,它只能用于刪除軟件包,如果 Qt 開發環境是用在線安裝方式裝的,這個工具還可以管理開發環境組件和升級組件。

    Qt 類庫的幫助文件位于 Docs 文件夾里,需要用 Qt Assistant 工具才能查看。

    Examples 里是示例代碼,可以用 QtCreator 集成開發環境打開各個示例。

    Qt 類庫目錄

    下面我們再探究一下 Qt 類庫目錄(~.9\mingw53_32\)的結構,如下圖所示。

    圖2:Qt 類庫目錄

    圖上列的比較有限,不一定全面,主要是教大家熟悉一下 Qt 的開發環境。

    認識一下Qt用到的開發工具

    Qt 不是憑空產生的,它是基于現有工具鏈打造而成的,它所使用的編譯器、鏈接器、調試器等都不是自己的,Qt 官方只是開發了上層工具。下面我們分幾個部分講解 Qt 使用到的工具鏈。


    GNU 工具集

    在上個世紀八十年代,計算機都是奢侈品,操作系統里最著名的是 Unix 家族, 當時還沒有 Windows、Linux 之類的,Unix 系統都是商業軟件,里面的應用軟件也是商業軟件, 全是封閉的環境。

    系統程序員 Richard M. Stallman (RMS) 在此環境下創立了與眾不同的 GNU 項目 (GNU’s Not Unix) , 以及推進自由軟件發展的 Free Software Foundation (FSF) 自由軟件基金會。

    GNU 項目是為了創建自由的類 Unix 系統,也因此開發出來很多開源的系統工具,其中非常著名的就是 GCC (GNU Compiler Collection,GNU編譯器套件)。

    現在我們知道,GUN 開發類 Unix 系統的項目失敗了,但是它開發的一系列工具集卻用到了后來的 Linux 內核上,兩者結合形成了今天的各種 Linux 發行版

    在 GNU 工具集里面,開發時常見到的幾個羅列如下(這些工具通常位于 Linux 或 Unix 系統里的 /usr/bin/ 目錄):

    工具

    說明

    gcc

    GNU C 語言編譯器。

    g++

    GNU C++ 語言編譯器。

    ld

    GNU 鏈接器,將目標文件和庫文件鏈接起來,創建可執行程序和動態鏈接庫。

    ar

    生成靜態庫 .a ,可以編輯和管理靜態鏈接庫。

    make

    生成器,可以根據 makefile 文件自動編譯鏈接生成可執行程序或庫文件。

    gdb

    調試器,用于調試可執行程序。

    ldd

    查看可執行文件依賴的共享庫(擴展名 .so,也叫動態鏈接庫)。

    MinGW

    原本 GNU 工具只在 Linux/Unix 系統里才有,隨著 Windows 系統的廣泛使用, 為了在 Windows 系統里可以使用 GNU 工具,誕生了 MinGW(Minimalist GNU for Windows) 項目,利用 MinGW 就可以生成 Windows 里面的 exe 程序和 dll 鏈接庫。

    需要注意的是,MinGW 與 Linux/Unix 系統里 GNU 工具集的有些區別:

    MinGW 里面工具帶有擴展名 .exe, Linux/Unix 系統里工具通常都是沒有擴展名的。

    MinGW 里面的生成器文件名為 mingw32-make.exe,Linux/Unix 系統里就叫 make。

    MinGW 在鏈接時是鏈接到 *.a 庫引用文件,生成的可執行程序運行時依賴 *.dll,而 Linux/Unix 系統里鏈接時和運行時都是使用 *.so 。

    另外 MinGW 里也沒有 ldd 工具,因為 Windows 不使用 .so 共享庫文件。如果要查看 Windows 里可執行文件的依賴庫,需要使用微軟自家的 Dependency Walker 工具。Windows 里面動態庫擴展名為 .dll,MinGW 可以通過 dlltool 來生成用于創建和使用動態鏈接庫需要的文件,如 .def 和 .lib。

    MinGW 原本是用于生成 32 位程序的,隨著 64 位系統流行起來, 從 MinGW 分離出來了 MinGW-w64 項目,該項目同時支持生成 64 位和 32 位程序。Qt 的 MinGW 版本庫就是使用 MinGW-w64 項目里面的工具集生成的。

    MSYS(Minimal SYStem)

    另外提一下,由于 MinGW 本身主要就是編譯鏈接等工具和頭文件、庫文件,并不包含系統管理、文件操作之類的 Shell 環境, 這對希望用類 Unix 命令的開發者來說還是不夠用的。 所以 MinGW 官方又推出了 MSYS(Minimal SYStem),相當于是一個部署在 Windows 系統里面的小型 Unix 系統環境, 移植了很多 Unix/Linux 命令行工具和配置文件等等,是對 MinGW 的擴展。

    MSYS 對于熟悉 Unix/Linux 系統環境或者要嘗試學習 Unix/Linux 系統的人都是一種便利。MSYS 和 MinGW 的安裝升級都是通過其官方的 mingw-get 工具實現,二者是統一下載安裝管理的。
    【文章福利】:Qt開發學習資料包、Qt面試題文檔、項目視頻、學習路線,包括(Qt C++基礎,數據庫編程,Qt項目實戰、Qt框架、QML、Opencv、qt線程等等),免費分享,有需要的可以加君羊領取哦!~學習交流君羊937552610點擊加入領取資料

    對于 MinGW-w64 項目,它對應的小型系統環境叫 MSYS2(Minimal SYStem 2),MSYS2 是 MSYS 的衍生版,不僅支持 64 位系統和 32 位系統,還有自己的獨特的軟件包管理工具,它從 Arch Linux 系統里移植了 pacman 軟件管理工具,所以裝了 MSYS2 之后,可以直接通過 pacman 來下載安裝軟件,而且可以自動解決依賴關系、方便系統升級等。裝了 MSYS2 之后,不需要自己去下載 MinGW-w64,可以直接用 pacman 命令安裝編譯鏈接工具和 git 工具等。

    MinGW 項目主頁(含 MSYS): http://www.mingw.org/

    MinGW-w64 項目主頁: https://sourceforge.net/projects/mingw-w64/

    MSYS2 項目主頁: https://sourceforge.net/projects/msys2/

    CMake

    CMake(Cross platform Make)是一個開源的跨平臺自動化構建工具, 可以跨平臺地生成各式各樣的 makefile 或者 project 文件, 支持利用各種編譯工具生成可執行程序或鏈接庫。

    CMake 自己不編譯程序, 它相當于用自己的構建腳本 CMakeLists.txt,叫各種編譯工具集去生成可執行程序或鏈接庫。

    一般用于編譯程序的 makefile 文件比較復雜,自己去編寫比較麻煩, 而利用 CMake ,就可以編寫相對簡單的 CMakeLists.txt ,由 CMake 根據 CMakeLists.txt 自動生成 makefile,然后就可以用 make 生成可執行程序或鏈接庫。

    本教程里面是使用 Qt 官方的 qmake 工具生成 makefile 文件,沒有用 CMake。這里之所以提 CMake,是因為整個 KDE 桌面環境的茫茫多程序都是用 CMake 腳本構建的,另外跨平臺的程序/庫如 Boost C++ Libraries、OpenCV、LLVM、Clang 等也都是用 CMake 腳本構建的。以后如果接觸到這些東西,是需要了解 CMake 的。

    CMake 項目主頁:https://cmake.org/

    KDE 項目主頁:https://www.kde.org/

    Qt 工具集

    Qt 官方的開發環境安裝包里有自己專門的開發工具,之前用過 qmake 命令。qmake 是 Qt 開發最核心的工具,既可以生成 Qt 項目文件 .pro ,也可以自動生成項目的 Makefile 文件。

    這里將常用的 Qt 開發工具列表如下:

    工具

    說明

    qmake

    核心的項目構建工具,可以生成跨平臺的 .pro 項目文件,并能依據不同操作系統和編譯工具生成相應的 Makefile,用于構建可執行程序或鏈接庫。

    uic

    User Interface Compiler,用戶界面編譯器,Qt 使用 XML 語法格式的 .ui 文件定義用戶界面,uic 根據 .ui 文件生成用于創建用戶界面的 C++ 代碼頭文件,比如 ui_*****.h 。

    moc

    Meta-Object Compiler,元對象編譯器,moc 處理 C++ 頭文件的類定義里面的 Q_OBJECT 宏,它會生成源代碼文件,比如 moc_*****.cpp ,其中包含相應類的元對象代碼,元對象代碼主要用于實現 Qt 信號/槽機制、運行時類型定義、動態屬性系統。

    rcc

    Resource Compiler,資源文件編譯器,負責在項目構建過程中編譯 .qrc 資源文件,將資源嵌入到最終的 Qt 程序里。

    qtcreator

    集成開發環境,包含項目生成管理、代碼編輯、圖形界面可視化編輯、 編譯生成、程序調試、上下文幫助、版本控制系統集成等眾多功能, 還支持手機和嵌入式設備的程序生成部署。

    assistant

    Qt 助手,幫助文檔瀏覽查詢工具,Qt 庫所有模塊和開發工具的幫助文檔、示例代碼等都可以檢索到,是 Qt 開發必備神器,也可用于自學 Qt。

    designer

    Qt 設計師,專門用于可視化編輯圖形用戶界面(所見即所得),生成 .ui 文件用于 Qt 項目。

    linguist

    Qt 語言家,代碼里用 tr() 宏包裹的就是可翻譯的字符串,開發人員可用 lupdate 命令生成項目的待翻譯字符串文件 .ts,用 linguist 翻譯多國語言 .ts ,翻譯完成后用 lrelease 命令生成 .qm 文件,然后就可用于多國語言界面顯示。

    qmlscene

    在 Qt 4.x 里是用 qmlviewer 進行 QML 程序的原型設計和測試,Qt 5 用 qmlscene 取代了舊的 qmlviewer。新的 qmlscene 另外還支持 Qt 5 中的新特性 scenegraph 。

    Qt編程涉及的術語和名詞

    本節我們來介紹一下使用 Qt 編程過程中常用的術語和名字,它們不一定專屬于 Qt,在其它的 C/C++ 開發過程中也會使用到。

    Project

    Project 的中文翻譯是“項目”或者“工程”,這里的項目是指為實現某個相對獨立功能的程序代碼合集,這些代碼不單單是放在一塊,而是有相互之間的關聯性,并且有專門負責管理該項目的項目文件,比如:

    Qt 使用 .pro 文件管理項目;

    VC++ 則使用 .vcproj 作為項目文件。

    集成開發環境通常都是依據項目文件(.pro/.vcproj)管理和構建項目。

    Makefile

    即生成腳本,雖然可以直接調用編譯器如 g++ 編譯程序,但是如果項目里的代碼文件變多了,哪些代碼文件更新了需要重新編譯,哪些代碼沒有改不需要重新編譯等等,靠程序員自己記憶去處理是比較麻煩的事,還有哪些代碼需要預處理或是鏈接哪些庫文件, 這些都是繁雜的過程。為了規范程序的編譯生成過程,產生了規范化的生成腳本,就是 Makefile,生成器 make 可以依據規范的 Makefile 自動生成目標程序或庫文件。

    簡單的說,就是定義好 Makefile ,讓程序員只需要去關注如何編寫代碼,而生成程序過程中的臟活累活都交給 make 程序。

    現在 Makefile 通常都有工具自動生成,如 qmake 工具, 這樣就大量減輕了程序員的負擔。

    Debug 和 Release

    Debug 即調試,Release 即發行。代碼編寫之后,生成的目標程序或庫文件通常不會絕對正確,或多或少有些毛?。╞ug), 因此需要進行糾錯調試(Debug)。調試過程中需要源代碼和二進制目標程序之間一一對應的關系, 這樣才能定位到錯誤代碼,所以 Debug 版本的程序是臃腫而不進行優化的。

    與之相對的是 Release 發行版,在糾正了發覺到的錯誤后,需要發布程序用于實際用途,實際應用時強調運行效率高,減少冗余代碼,因此會對二進制程序進行大量優化,提升性能。這樣發布的二進制目標程序就是 Release 版。

    Debug 版本和 Release 版本使用的庫文件不一樣:

    Debug 版本程序通常鏈接的也是 Debug 版本的庫文件,比如 libQt5Guid.a/Qt5Guid.dll,庫文件的簡短名(不含擴展名)都是以 d 結尾的,Debug 庫通常都比較大 。

    Release 版本程序鏈接的通常就是 Release 版本的庫文件,Release 版本庫文件名字比 Debug 版本庫文件少一個字母 d ,如 libQt5Gui.a/Qt5Gui.dll,而且 Release 版本庫一般都比 Debug 版本小很多,運行效率也高很多。

    C++11 標準

    時代在變化,C++ 標準也在前進。C++ 正式公布標準有 C++98、C++03、C++11。最新的 C++11 標準是2011年8月12日公布的,在公布之前該標準原名為 C++0x 。這是一次較大的修訂和擴充,建議讀者專門學一下。

    Qt 從 4.8 版本就開始用 C++11 新特性了。編譯器里面開始支持 C++11 的版本是 MSVC 2010、GCC 4.5、Clang 3.1,這之后版本的編譯器都在逐步完善對 C++11 的支持,現在新版本編譯器對新標準的支持都比較全面了。

    Qt 官方在編譯 Qt5 庫的時候都是開啟 C++11 特性的,如果我們要在自己項目代碼啟用新標準,需要在 .pro 文件里面添加一行:

    CONFIG += c++11

    如果是 Qt4 版本則是添加:

    gcc:CXXFLAGS += -std=c++0x

    MSVC 編譯器默認開啟 C++11 特性,GCC(g++命令)則需要自己添加選項 -std=c++0x ,上面 CXXFLAGS 就是為 GCC 編譯器(g++命令)添加 -std=c++0x 選項。

    Dynamic Link 和 Static Link

    Dynamic Link 即動態鏈接,Static Link 即靜態鏈接。

    動態鏈接庫

    目標程序通常都不是獨立個體,生成程序時都需要鏈接其他的庫,要用到其他庫的代碼。對于多個程序同時運行而言,內存中就可能有同一個庫的多個副本,占用了太多內存而干的活差不多。

    為了優化內存運用效率,引入了動態鏈接庫(Dynamic Link Library),或叫共享庫(Shared Object)。使用動態鏈接庫時,內存中只需要一份該庫文件,其他程序要使用該庫文件時,只要鏈接過來就行了。由于動態庫文件外置,鏈接到動態庫的目標程序相對比較小,因為剝離了大量庫代碼,而只需要一些鏈接指針。

    使用動態庫,也意味著程序需要鏈接到如 *.dll 或 *.so 文件,得提前裝好動態庫文件,然后目標程序才能正常運行。

    靜態鏈接庫

    靜態庫就是將鏈接庫的代碼和自己編寫的代碼都編譯鏈接到一塊,鏈接到靜態庫的程序通常比較大,但好處是運行時依賴的庫文件很少,因為目標程序自己內部集成了很多庫代碼。

    庫文件后綴

    Linux/Unix 系統里靜態庫擴展名一般是 .a,動態庫擴展名一般是 .so 。Windows 系統里 VC 編譯器用的靜態庫擴展名一般是 .lib,動態庫擴展名一般是 .dll 。

    MinGW 比較特殊,是將 GNU 工具集和鏈接庫從 Linux/Unix 系統移植到 Windows 里, 有意思的情況就出現了,MinGW 使用的靜態庫擴展名為 .a ,而其動態庫擴展名則為 .dll, .a 僅在生成目標程序過程中使用,.dll 則是在目標程序運行時使用。

    Explicit Linking 和 Implicit Linking

    Explicit Linking 即顯式鏈接,Implicit Linking 即隱式鏈接,這兩種都是動態鏈接庫的使用方式。

    動態鏈接庫通常都有其導出函數列表, 告知其他可執行程序可以使用它的哪些函數。可執行程序使用這些導出函數有兩種方式:一是在運行時使用主動加載動態庫的函數,Linux 里比如用 dlopen 函數打開并加載動態庫,Windows 里一般用 LoadLibrary 打開并加載動態庫,只有當程序代碼執行到這些函數時,其參數里的動態庫才會被加載,這就是顯式鏈接。顯式鏈接方式是在運行時加載動態庫,其程序啟動時并不檢查這些動態庫是否存在。

    隱式鏈接是最為常見的,所有的編譯環境默認都是采用隱式鏈接的方式使用動態庫。隱式鏈接會在鏈接生成可執行程序時就確立依賴關系,在該程序啟動時,操作系統自動會檢查它依賴的動態庫,并一一加載到該程序的內存空間,程序員就不需要操心什么時候加載動態庫了。比如 VC 編譯環境,鏈接時使用動態庫對應的 .lib 文件(包含動態庫的導出函數聲明,但沒有實際功能代碼),在 .exe 程序運行前系統會檢查依賴的 .dll,如果找不到某個動態庫就會出現類似下圖對話框:

    MinGW 是將動態庫的導出函數聲明放在了 .a 文件里,程序運行依賴的動態庫也是 .dll 。

    請注意,VC 鏈接器使用的 .lib 文件分兩類,一種是完整的靜態庫,體積比較大,另一種是動態庫的導出聲明,體積比較小。MinGW 鏈接器使用的 .a 文件也是類似的,Qt 官方庫都是按照動態庫發布的,靜態庫只有自己編譯才會有。

    Qt Creator的初步使用

    啟動 Qt Creator,出現如圖 1 所示的主窗口:

    圖 1 Qt Creator主窗口

    Qt Creator 的界面很簡潔。上方是主菜單欄,左側是主工具欄,窗口的中間部分是工作區。根據設計內容不同,工作區會顯示不同的內容。

    圖 1 是在左側主工具欄單擊“Welcome(歡迎)”按鈕后顯示實例的界面。這時工作區的左側有 “Projects”、“Examples(示例)”、“Tutorials(教程)”、“Get Started Now”幾個按鈕,單擊后會在主工作區顯示相應的內容:

    單擊“Projects”按鈕后,工作區顯示新建項目按鈕和最近打開項目的列表。

    單擊“Examples(示例)”按鈕后,工作區顯示 Qt 自帶的大量實例,選擇某個實例就可以在 Qt Creator 中打開該項目源程序。

    單擊“Tutorials(教程)”按鈕后,工作區顯示各種視頻教程,查看視頻教程需要聯網并使用瀏覽器打開。

    單擊“Get Started Now”按鈕,工作區顯示“Qt Creator Manual”幫助主題內容。

    主窗口左側是主工具欄,主工具欄提供了項目文件編輯、窗體設計、程序調試、項目設置等各種功能按鈕。

    Qt Creator 的設置

    對 Qt Creator 可以進行一些設置,如剛安裝好的 Qt Creator 界面語言可能是中文,也可以選擇將 Qt Creator 的界面語言設置為英文。

    圖 2 Options 的構建和運行設置頁面

    單擊 Qt Creator 菜單欄的 Tools→Options 菜單項會打開選項設置對話框(如圖 2 所示)。對話框的左側是可設置的內容分組,單擊后右側出現具體的設置界面。常用的設置包括以下幾點:

    Environment(環境) 設置:在 Interface 頁面可以設置語言和主題,本教程全部以中文界面的 Qt Creator 進行講解,所以語言選擇為 Chinese(China);為了使界面抓圖更清晰,設置主題為 Flat Light。更改語言和主題后需要重新啟動 Qt Creator 才會生效。

    Text Editor(文本編輯器)設置:在此界面可以設置文本編輯器的字體,設置各種類型文字的字體顏色,如關鍵字、數字、字符串、注釋等字體顏色,也可以選擇不同的配色主題。編輯器缺省字體的大小為 9,可以修改得大一些。

    Build & Run(構建和運行)設置:圖 2 顯示的是 Build & Run 的設置界面,它有以下幾個頁面。

    Kits(構建套件)頁面顯示 Qt Creator 可用的編譯工具。

    Qt Versions 頁面顯示安裝的 Qt 版本。

    Compliers(編譯器)頁面顯示系統里可用的 C 和 C++ 編譯器,由于安裝了 MinGW 和 Visual Studio 2015,Qt Creator 會自動檢測出這些編譯器。

    Debuggers 頁面顯示 Qt Creator 自動檢測到的調試器,有 GNU gdb for MinGW 調試器和 Windows 的 CDB 調試器。

    注意,如果只是在計算機上安裝了 Visual Studio 2015,圖 2 Kits 顯示的界面上 MSVC2015 的兩個編譯器的圖標會變為帶有感嘆號的一個黃色圖標。Debuggers 頁面沒有 Windows 的 CDB 調試器,可以用 MSVC 編譯器對 Qt Creator 編寫的程序進行編譯,但是不能調試,這是因為缺少了 Windows Software Development Kit (SDK)。這個 SDK 不會隨 Visual Studio 一同安裝,需要從 Microsoft 網站上下載??梢韵螺d Windows Software Development Kit (SDK) for Windows 8.1,安裝后重啟計算機即可。

    編寫第一個Qt程序

    學習一種編程語言或編程環境,通常會先編寫一個“Hello World”程序。我們也用 Qt Creator 編寫一個“Hello World”程序,以初步了解 Qt Creator 設計應用程序的基本過程,對使用 Qt Creator 編寫 Qt C++ 應用程序建立初步的了解。

    新建一個項目

    單擊 Qt Creator 的菜單項文件->新建文件或項目,出現如圖 1 所示的對話框。在這個對話框里選擇需要創建的項目或文件的模板。

    圖 1 新建文件或項目對話框

    Qt Creator 可以創建多種項目,在最左側的列表框中單擊“Application”,中間的列表框中列出了可以創建的應用程序的模板,各類應用程序如下:

    Qt Widgets Application,支持桌面平臺的有圖形用戶界面(Graphic User Interface,GUI) 界面的應用程序。GUI 的設計完全基于 C++ 語言,采用 Qt 提供的一套 C++ 類庫。

    Qt Console Application,控制臺應用程序,無 GUI 界面,一般用于學習 C/C++ 語言,只需要簡單的輸入輸出操作時可創建此類項目。

    Qt Quick Application,創建可部署的 Qt Quick 2 應用程序。Qt Quick 是 Qt 支持的一套 GUI 開發架構,其界面設計采用 QML 語言,程序架構采用 C++ 語言。利用 Qt Quick 可以設計非常炫的用戶界面,一般用于移動設備或嵌入式設備上無邊框的應用程序的設計。

    Qt Quick Controls 2 Application,創建基于 Qt Quick Controls 2 組件的可部署的 Qt Quick 2 應用程序。Qt Quick Controls 2 組件只有 Qt 5.7 及以后版本才有。

    Qt Canvas 3D Application,創建 Qt Canvas 3D QML 項目,也是基于 QML 語言的界面設計,支持 3D 畫布。

    在圖 1 顯示的對話框中選擇項目類型為 Qt Widgets Application 后,單擊“Choose…”按鈕,出現如圖 2 所示的新建項目向導:

    圖 2 新建項目向導第 1 步:項目名稱和項目存儲位置設置

    在圖 2 中,選擇一個目錄,如“E:\QtDemo”,再設置項目名稱為 Demo, 這樣新建項目后,會在“E:\QtDemo”目錄下新建一個目錄,項目所有文件保 存在目錄“E:\QtDemo\Demo\”下。

    在圖 2 中設置好項目名稱和保存路徑后,單擊“Next”按鈕,出現如圖 3 所示的選擇編譯工具的界面:

    圖 3 新建項目向導第 2 步:選擇編譯工具

    可以將這幾個編譯工具都選中,在編譯項目時再選擇一個作為當前使用的編譯工具,這樣可以編譯生成不同版本的可執行程序。

    圖 4 新建項目想到第 3 步:選擇界面基類

    在圖 3 顯示的界面中單擊“Next”按鈕,出現如圖 4 所示的界面。在此界面中選擇需要創建界面的基類(base class)。有 3 種基類可以選擇:

    QMainWindow 是主窗口類,主窗口具有主菜單欄、工具欄和狀態欄,類似于一般的應用程序的主窗口;

    QWidget 是所有具有可視界面類的基類,選擇 QWidget 創建的界面對各種界面組件都可以 支持;

    QDialog 是對話框類,可建立一個基于對話框的界面;

    在此選擇 QMainWindow 作為基類,自動更改的各個文件名不用手動去修改。勾選“創建界面”復選框。這個選項如果勾選,就會由 Qt Creator 創建用戶界面文件,否則,需要自己編程手工創建界面。初始學習,為了了解 Qt Creator 的設計功能,勾選此選項。

    然后單擊“Next”按鈕,出現一個頁面,總結了需要創建的文件和文件保存目錄,單擊“完成”按鈕就可以完成項目的創建。

    項目的文件組成和管理

    完成了以上新建項目的步驟后,在 Qt Creator 的左側工具欄中單擊“編輯”按鈕,可顯示如圖 5 所示的窗口。

    圖 5 項目管理與文件編輯界面

    窗口左側有上下兩個子窗口,上方的目錄樹顯示了項目內文件的組織結構,顯示當 前項目為 Demo。項目的名稱構成目錄樹的一個根節點,Qt Creator 可以打開多個項目,但是只有一個活動項目,活動項目的項目名稱節點用粗體字體表示。

    在項目名稱節點下面,分組管理著項目內的各種源文件,幾個文件及分組分別為以下幾項:

    Demo.pro 是項目管理文件,包括一些對項目的設置項。

    Headers 分組,該節點下是項目內的所有頭文件(.h),圖 5 中所示項目有一個頭文件 mainwindow.h,是主窗口類的頭文件。

    Sources 分組:該節點下是項目內的所有 C++源文件(.cpp),圖 5 中所示項目有兩個 C++ 源文件,mainwindow.cpp 是主窗口類的實現文件,與 mainwindow.h 文件對應。main.cpp 是主函數文件,也是應用程序的入口。

    Forms 分組:該節點下是項目內的所有界面文件(.ui)。圖 5 中所示項目有一個界面文件mainwindow.ui,是主窗口的界面文件。界面文件是文本文件,使用 XML 語言描述界面的組成。

    左側上下兩個子窗口的顯示內容可以通過其上方的一個下拉列表框進行選擇,可以選擇的顯示內容包括項目、打開文檔、書簽、文件系統、類視圖、大綱等。在圖 5 中,上方的子窗口顯示了項目的文件目錄樹,下方顯示打開的文件列表。可以在下方選擇顯示類視圖,這樣下方則顯示項目內所有的類的結構,便于程序瀏覽和快速切換到需要的代碼位置。

    雙擊文件目錄樹中的文件mainwindow.ui,出現如圖 6 所示的窗體設計界面:

    圖 6 集成在 Qt Creator 中UI設計器

    這個界面實際上是 Qt Creator 中集成的 Qt Designer。窗口左側是分組的組件面板,中間是設計的窗體。在組件面板的 Display Widgets 分組里,將一個Label組件拖放到設計的窗體上面。雙擊剛剛放置的 Label 組件,可以編輯其文字內容,將文字內容更改為“Hello, World!”。還可以在窗口右下方的屬性編輯器里編輯標簽的 Font 屬性,Point Size(點大小)更改為 12,勾選粗體。

    項目的編譯、調試與運行

    單擊主窗口左側工具欄上的“項目”按鈕,出現如圖 7 所示的項目編譯設置界面。

    圖 7 項目編譯器選擇和設置界面

    界面左側一欄的“Build & Run”下面顯示了本項目中可用的編譯器工具,要使用哪一個編譯器用于項目編譯,單擊其名稱即可,選擇的編譯器名稱會用粗體字表示。這里選擇使用 MinGW 32bit 編譯器。

    每個編譯器又有 Build 和 Run 兩個設置界面。在 Build 設置界面上,有一個“Shadow build” 復選框。如果勾選此項,編譯后將在項目的同級目錄下建立一個編譯后的文件目錄,目錄名稱包含編譯器信息,這種方式一般用于使用不同編譯器創建不同版本的可執行文件。如果不勾選此項,編譯后將在項目的目錄下建立“Debug”和“Release”子目錄用于存放編譯后的文件。

    在設計完 mainwindow.ui 文件,并設置好編譯工具之后,就可以對項目進行編譯、調試或運行。主窗口左側工具欄下方有 4 個按鈕,其功能見表 1。

    圖標

    作用

    快捷鍵

    電腦img

    彈出菜單選擇編譯工具和編譯模式,如 Debug或 Release模式

    綠三角img

    直接運行程序,如果修改后未編譯,會先進行編譯。即使在程序中設置了斷點,此方式運行的程序也無法調試。

    Ctrl+R

    綠三角甲蟲img

    項目需要以Debug模式編譯,點此按鈕開始調試運行,可以在程序中設置斷點。若是以 Release模式編譯,點此按鈕也無法進行調試。

    F5

    錘子img

    編譯當前項目

    Ctrl+B

    首先對項目進行編譯,沒有錯誤后,再運行程序。程序運行的界面如圖 8 所示。這就是一個標準的桌面應用程序,我們采用可視化的方式設計了一個窗口,并在上面顯示了字符串“Hello, World!”。

    圖 8 實例程序 Demo 運行時界面

    在 Qt Creator 中也可以對程序設置斷點進行調試,但是必須以 Debug 模式編譯,并以“Start Debugging”(快捷鍵 F5)方式運行程序。

    程序調試的方法與一般 IDE 工具類似,不再詳述。注意,要在 Qt Creator 里調試 MSVC2015 編譯的程序,必須安裝 Windows 軟件開發工具包 SDK。

    分析第一個Qt程序

    前面章節中,通過在 xxx.ui 文件中拖拽 Label 組件,設計出了一個顯示 “Hello,World!” 的窗口,如下圖所示:



    圖 1 簡單的界面

    本節我們完全舍棄 xxx.ui 文件,親手編寫代碼實現圖 1 所示的界面。

    創建項目

    首先,打開 Qt Creator 并創建一個 Qt Widgets Application 項目。需要注意的是,我們要創建一個不帶 xxx.ui 文件的項目,如下圖所示:

    圖 2 創建不帶 ui 文件的圖形界面項目

    最終創建的項目結構如下圖所示:

    圖 3 項目結構

    Demo.pro 是項目文件,文件中的內容可以手動修改,本節不需要修改此文件。接下來,我們逐一介紹 main.cpp、mainwindow.h 和 mainwindow.cpp 這 3 個文件。

    1) main.cpp

    main.cpp 是主函數文件,內部主要包含應用程序的入口函數,也就是 main() 函數。

    我們知道,C/C++ 程序中 main() 函數的語法格式是固定的:

    int main(int argc, char *argv[]){
        //填充代碼
        return 0;
    }

    Qt 界面程序中的 main() 函數也有固定的格式:

    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        //填充代碼
        return a.exec();
    }
    

    對于剛剛學習 Qt 的讀者,暫時不用了解第 3 行和第 5 行代碼的含義,只要記住:使用 Qt 框架編寫帶界面的應用程序,main() 函數中必須包含第 3 行和第 5 行代碼,否則程序無法正常運行。

    雙擊圖 3 所示的 main.cpp 文件,可以看到該文件包含的所有代碼:

    #include "mainwindow.h"
    #include <QApplication>
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        w.show();
        return a.exec();
    }
    

    除了第 6、8 行代碼外,其它代碼的含義分別是:

    1~2 行:由于 main() 函數中分別定義了 QApplication 和 MainWindow 類的對象,因此需要引入 mainwindows.h 和 QApplication 頭文件。mainwindow.h 文件是我們自己創建的,引入時用" "雙引號括起來;QApplication 是 Qt 提供給我們的,引入時用<>括起來。

    第 7 行:MainWindow 是自定義的類,繼承自 QMainWindow 主窗口類,因此 MainWindow 也是一個主窗口類。w 是 MainWindow 類實例化出的對象,表示一個主窗口。

    第 8 行:默認情況下,Qt 提供的所有組件(控件、部件)都是隱藏的,不會自動顯示。通過調用 MainWindow 類提供的 show() 方法,w 窗口就可以在程序運行后顯示出來。

    2) mainwindow.h和mainwindow.cpp

    創建項目時,我們在圖 2 所示的對話框中定義了一個繼承自 QMainWindow 的主窗口類,并起名為 MianWindow,該類的定義部分位于 mainwindow.h 頭文件中,實現部分位于 mainwindow.cpp 源文件中。

    雙擊圖 3 所示的 mainwindow.h 和 mainwindow.cpp 文件,可以看到它們各自包含的代碼:

    //mainwindow.h
    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    #include <QMainWindow>
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    public:
        MainWindow(QWidget *parent = 0);
        ~MainWindow();
    };
    //mainwindow.cpp
    #endif // MAINWINDOW_H
    #include "mainwindow.h"
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
    {
    }
    MainWindow::~MainWindow()
    {
    }
    

    初始狀態下,MainWindow 類由 Q_OBJECT、構造函數和析構函數組成,這里重點介紹一下 Q_OBJECT 和構造函數:

    Q_OBJECT:本質是一個已定義好的宏,所有需要“信號和槽”功能的組件都必須將 Q_OBJECT 作為 private 屬性成員引入到類中。本節設計的界面程序不會用到“信號和槽”,因此可以刪除 Q_OBJECT。有關信號和槽,我們會在《Qt信號和槽機制詳解》一節詳細介紹。

    帶參的構造函數:QWidget 是所有組件的基類,借助 parent 指針,可以為當前窗口指定父窗口。例如圖 1 中,QLabel 文本框位于主窗口中,主窗口就是它的父窗口。當父窗口被刪除時,所有子窗口也會隨之一起刪除。當然也可以不指定父窗口,那么當前窗口就會作為一個獨立的窗口,不會受到其它窗口的影響。

    直接運行程序,會輸出下圖所示的界面:

    圖 4 空白主窗口

    圖 4 看到的就是 main() 函數中創建的 w 主窗口。由于沒有往 w 窗口中放置任何組件,所以 w 是一個空白窗口。

    編碼實現簡易的窗口界面

    我們嘗試向 w 主窗口添加一個文本框,需要對 MainWindow 類進行修改。修改后的 MainWindow 類如下:

    //mainwindow.h
    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    #include <QMainWindow>
    #include <QLabel>      // 引入 QLable 文件框組件的頭文件
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    public:
        MainWindow(QWidget *parent = 0);
        ~MainWindow();
    private:
        QLabel *lab;        // 定義一個私有的 QLabel 指針對象
    };
    #endif // MAINWINDOW_H
    //mainwindow.cpp
    #include "mainwindow.h"
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
    {
        // 創建一個 QLable 對象
        this->lab = new QLabel("Hello,World!",this);
    }
    MainWindow::~MainWindow()
    {
    }
    

    和先前空的 MainWindow 類相比,做了如下修改:

    添加了一個 QLabel 類的指針對象,相應地要引入<QLabel>頭文件;

    在構造函數中定義了一個 QLabel 類的文本框對象,通過調用它的帶參構造函數,設置它的父對象為當前類的對象,同時設置 “Hello,World!” 為要顯示的文本信息。

    再次運行程序,顯示的窗口如下圖所示:

    圖 5 帶文本框的主窗口

    圖 1 和圖 5 是類似的,區別在于圖 5 中的 “Hello, World!” 沒有加粗,也沒有調整它在主窗口中的位置,這些都可以通過編碼實現,后續講 QLabel 時會做詳細介紹。

    圖 5 中,“Hello,World!” 文本框的父窗口是主窗口,所以文本框位于主窗口中(位置默認在窗口的左上角),主窗口關閉時文本框也會隨之關閉。

    由此,我們就成功設計了一個包含文本框的窗口,這也是我們編寫的第一個 Qt 程序。

    Qt控件和事件

    Qt 是一個著名的 GUI 框架,用來開發和用戶交互的圖形界面。作為 GUI 框架,豐富的控件和靈活的事件機制是不可或缺的,Qt 在這一方面做得非常優秀。

    什么是 Qt 控件

    Qt 控件又稱組件或者部件,指用戶看到的所有可視化界面以及界面中的各個元素,比如按鈕、文本框、輸入框等。

    為了方便程序員開發,Qt 提供了很多現成的控件。打開某個帶 ui 文件的 Qt Widgets Application 項目,ui 文件的 Widget Box 一欄展示了 Qt 提供的幾乎所有控件:

    圖 1 Qt 提供的控件

    Qt 中的每個控件都由特定的類表示,每個控件類都包含一些常用的屬性和方法,所有的控件類都直接或者間接繼承自 QWidget 類。實際開發中,我們可以使用 Qt 提供的這些控件,也可以通過繼承某個控件類的方式自定義一個新的控件。

    前面說過,Qt 中所有可視化的元素都稱為控件,我們習慣將帶有標題欄、關閉按鈕的控件稱為窗口。例如,下圖展示了兩種常用的窗口,實現它們的類分別是 QMainWindow 和 QDialog。


    圖 2 Qt 窗口

    QMainWindow 類生成的窗口自帶菜單欄、工具欄和狀態欄,中央區域還可以添加多個控件,常用來作為應用程序的主窗口;

    QDialog 類生成的窗口非常簡單,沒有菜單欄、工具欄和狀態欄,但可以添加多個控件,常用來制作對話框。

    除了 QMainWindow 和 QDialog 之外,還可以使用 QWidget 類,它的用法非常靈活,既可以用來制作窗口,也可以作為某個窗口上的控件。

    窗口很少單獨使用,它的內部往往會包含很多控件。例如圖 2 中,我們分別往 MainWindow 和 Dialog 窗口中放置了一個按鈕控件,根據需要還可以放置更多的控件。當窗口彈出時,窗口包含的所有控件會一同出現;當窗口關閉時,窗口上的所有控件也會隨之消失。

    實際開發中,制作應用程序的主窗口可以用 QMainWindow 或者 QWdiget;制作一個提示信息的對話框就用 QDialog 或 QWidget;如果暫時無法決定,后續可能作為窗口,也可能作為控件,就選擇 QWidget。

    什么是Qt事件

    簡單地理解,Qt 事件指的是應用程序和用戶之間的交互過程,例如用戶按下某個按鈕,點擊某個輸入框等等。實際上除了用戶會與應用程序進行交互外,操作系統也會與應用程序進行交互,例如當某個定時任務觸發時,操作系統會關閉應用程序,這也是一個事件。

    Qt 界面程序的 main() 主函數中首先要創建一個 QApplication 類的對象,函數執行結束前還要調用 QApplication 對象的 exec() 函數。一個 Qt 界面程序要想接收事件,main() 函數中就必須調用 exec() 函數,它的功能就是使程序能夠持續不斷地接收各種事件。

    Qt 程序可以接收的事件種類有很多,例如鼠標點擊事件、鼠標滾輪事件、鍵盤輸入事件、定時事件等。每接收一個事件,Qt 會分派給相應的事件處理函數來處理。所謂事件處理函數,本質就是一個普通的類成員函數,以用戶按下某個 QPushButton 按鈕為例,Qt 會分派給 QPushButton 類中的 mousePressEvent() 函數處理。

    事件處理函數通常會完成兩項任務,分別是:

    • 修改控件的某些屬性,比如當用戶按下按鈕時,按鈕的背景顏色會發生改變,從而提示用戶已經成功地按下了按鈕;
    • 運用信號和槽機制處理事件。

    創建一個不帶 ui 文件的 Qt Widgets Application 項目,項目中只保留一個 main.cpp 源文件,刪除其它文件(mainwindows.h 和 mainwindow.cpp)。將下述代碼直接拷貝到 main.cpp 文件:

    //main.cpp
    #include <QApplication>
    #include <QWidget>
    #include <QPushButton>
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        //添加窗口
        QWidget widget;
        //定義一個按鈕,它位于 widget 窗口中
        QPushButton But("按鈕控件",&widget);
        //設置按鈕的位置和尺寸
        But.setGeometry(10,10,100,50);
        //信號與槽,實現當用戶點擊按鈕時,widget 窗口關閉
        QObject::connect(&But,&QPushButton::clicked,&widget,&QWidget::close);
        //讓 widget 窗口顯示
        widget.show();
        return a.exec();
    }
    

    運行結果如下圖所示:

    圖 3 運行結果

    整個程序的運行過程如下:

    先創建了一個 QWidget 窗口,在窗口上添加一個 QPushButton 按鈕;

    當用戶點擊按鈕時,Qt 會將此事件分派給 QPushButton 類的 mousePressEvent() 事件處理函數;

    mousePressEvent()函數內部會改變按鈕的屬性,提示用戶成功按下了按鈕,還會調用 clicked() 函數發出“用戶點擊按鈕”的信號。對于發出的信號,程序中調用 connect() 函數指定 QWidget 類的 close() 函數接收 clicked() 信號,close() 函數會關閉 widget 窗口。

    總結

    實際開發中,我們用各種 Qt 控件設計出功能豐富的界面,用 Qt 事件完成與用戶的交互。學習 Qt 界面編程,本質上就是學習 Qt 各個控件的用法以及對 Qt 事件的處理。本節我們只是對 Qt 控件和事件做了簡單的了解,接下來將為您系統地講解它們的用法。

    Qt信號和槽機制詳解

    信號和槽是 Qt 特有的消息傳輸機制,它能將相互獨立的控件關聯起來。

    舉個簡單的例子,按鈕和窗口本是兩個獨立的控件,點擊按鈕并不會對窗口造成任何影響。通過信號和槽機制,我們可以將按鈕和窗口關聯起來,實現“點擊按鈕會使窗口關閉”的效果。

    信號和槽

    在 Qt 中,用戶和控件的每次交互過程稱為一個事件,比如“用戶點擊按鈕”是一個事件,“用戶關閉窗口”也是一個事件。每個事件都會發出一個信號,例如用戶點擊按鈕會發出“按鈕被點擊”的信號,用戶關閉窗口會發出“窗口被關閉”的信號。

    Qt 中的所有控件都具有接收信號的能力,一個控件還可以接收多個不同的信號。對于接收到的每個信號,控件都會做出相應的響應動作。例如,按鈕所在的窗口接收到“按鈕被點擊”的信號后,會做出“關閉自己”的響應動作;再比如輸入框自己接收到“輸入框被點擊”的信號后,會做出“顯示閃爍的光標,等待用戶輸入數據”的響應動作。在 Qt 中,對信號做出的響應動作就稱為槽。

    圖 1 信號和槽

    信號和槽機制底層是通過函數間的相互調用實現的。每個信號都可以用函數來表示,稱為信號函數;每個槽也可以用函數表示,稱為槽函數。例如,“按鈕被按下”這個信號可以用 clicked() 函數表示,“窗口關閉”這個槽可以用 close() 函數表示,信號和槽機制實現“點擊按鈕會關閉窗口”的功能,其實就是 clicked() 函數調用 close() 函數的效果。

    信號函數和槽函數通常位于某個類中,和普通的成員函數相比,它們的特別之處在于:

    信號函數用 signals 關鍵字修飾,槽函數用 public slots、protected slots 或者 private slots 修飾。signals 和 slots 是 Qt 在 C++ 的基礎上擴展的關鍵字,專門用來指明信號函數和槽函數;

    信號函數只需要聲明,不需要定義(實現),而槽函數需要定義(實現)。

    為了提高程序員的開發效率,Qt 的各個控件類都提供了一些常用的信號函數和槽函數。例如 QPushButton 類提供了 4 個信號函數和 5 個 public slots 屬性的槽函數,可以滿足大部分場景的需要。

    Qt Creator 提供了很強大的 Qt GUI 開發手冊,很容易就能查到某個控件類中包含哪些信號函數和槽函數。舉個例子,查看 QPushButton 類中信號函數和槽函數的過程是:

    在程序中引入<QPushButton>頭文件,雙擊選中“QPushButton”并按 “Fn+F1” 快捷鍵,就會彈出 QPushButton 類的使用手冊,如下圖所示。

    圖 2 QPushButton類的使用說明

    在 Contents 部分可以看到,QPushButton 類只提供了一些Public Slots屬性的槽函數,沒有提供信號函數。對于 QPushButton 類按鈕,除了可以使用自己類提供的槽函數,還可以使用從父類繼承過來的信號函數和槽函數。由圖 2 可知,QPushButton 的父類是 QAbstractButton,點擊 QAbstractButton 就可以直接跳轉到此類的使用手冊,如下圖所示:

    圖 3 QPushButton父類使用說明

    QAbstractButton 類中既有 Signals 信號函數,也有 Public Slots 槽函數,這里不再一一列舉,感興趣的讀者可以自行查看。

    注意,并非所有的控件之間都能通過信號和槽關聯起來,信號和槽機制只適用于滿足以下條件的控件:

    控件類必須直接或者間接繼承自 QObject 類。Qt 提供的控件類都滿足這一條件,這里提供一張 Qt常用類的繼承關系的高清圖片,感興趣的讀者可以簡單了解一下。

    控件類中必須包含 private 屬性的 Q_OBJECT 宏。

    將某個信號函數和某個槽函數關聯起來,需要借助 QObject 類提供的 connect() 函數。

    connect()函數實現信號和槽

    connect() 是 QObject 類中的一個靜態成員函數,專門用來關聯指定的信號函數和槽函數。

    關聯某個信號函數和槽函數,需要搞清楚以下 4 個問題:

    信號發送者是誰?

    哪個是信號函數?

    信號的接收者是誰?

    哪個是接收信號的槽函數?

    仍以實現“按下按鈕后窗口關閉”為例,先創建一個窗口和一個按鈕,如下所示:

    QWidget widget;
    //定義一個按鈕,它位于 widget 窗口中
    QPushButton But("按鈕控件",&widget);
    

    信號發送者是 But 按鈕對象,要發送的信號是“按鈕被點擊”,可以用 QPushButton 類提供的 clicked() 信號函數表示;信號的接收者是 widget 主窗口對象,“窗口關閉”作為信號對應的槽,可以用 QWidget 類提供的 close() 函數表示。

    在 Qt5 版本之前,connect() 函數最常用的語法格式是:

    QObject::connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection)

    各個參數的含義分別是:

    sender:指定信號的發送者;

    signal:指定信號函數,信號函數必須用 SIGNAL() 宏括起來;

    reveiver:指定信號的接收者;

    method:指定接收信號的槽函數,槽函數必須用 SLOT() 宏括起來;

    type 用于指定關聯方式,默認的關聯方式為 Qt::AutoConnection,通常不需要手動設定。

    用 connect() 函數將 But 按鈕的 clicked() 信號函數和 widget 窗口的 close() 槽函數關聯起來,實現代碼如下:

    connect(&But, SIGNAL(clicked()), &widget, SLOT(close()));

    如此就實現了“按下按鈕會關閉窗口”的功能。

    Qt5 版本中,connect() 函數引入了新的用法,常用的語法格式是:

    QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type = Qt::AutoConnection)

    和舊版本相比,新版的 connect() 函數改進了指定信號函數和槽函數的方式,不再使用 SIGNAL() 和 SLOT() 宏。

    例如,用新版 connect() 函數關聯 But 按鈕的 clicked() 信號函數和 widget 窗口的 close() 槽函數,實現代碼為:

    connect(&But, &QPushButton::clicked, &widget, &QWidget::close);

    可以看到,新版 connect() 函數指定信號函數和槽函數的語法格式是&+函數所在類+函數名。

    一個 connect() 函數只能關聯一個信號函數和一個槽函數,程序中可以包含多個 connect() 函數,能實現以下幾種效果:

    關聯多個信號函數和多個槽函數;

    一個信號函數可以關聯多個槽函數,當信號發出時,與之關聯的槽函數會一個接一個地執行,但它們執行的順序是隨機的,無法人為指定哪個先執行、哪個后執行;

    多個信號函數可以關聯同一個槽函數,無論哪個信號發出,槽函數都會執行。

    此外,connect() 函數的 method 參數還可以指定一個信號函數,也就是說,信號之間也可以相互關聯,這樣當信號發出時,會隨之發出另一個信號。

    實例演示信號和槽機制

    創建一個不含 ui 文件的 Qt Widgets Application 項目,只保留 main.cpp 源文件,刪除 mainwindow.h 和 mainwindow.cpp 文件。在 main.cpp 文件中編寫如下代碼:

    #include <QApplication>
    #include <QWidget>
    #include <QPushButton>
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        //添加窗口
        QWidget widget;
        //定義一個按鈕,它位于 widget 窗口中
        QPushButton But("按鈕控件",&widget);
        //設置按鈕的位置和尺寸
        But.setGeometry(10,10,100,50);
        //信號與槽,實現當用戶點擊按鈕時,widget 窗口關閉
        QObject::connect(&But,&QPushButton::clicked,&widget,&QWidget::close);
        //讓 widget 窗口顯示
        widget.show();
        return a.exec();
    }
    

    運行結果為:

    如上圖所示,由于使用了 conect() 函數將 But 的 clicked() 信號函數和 widget 的 close() 槽函數關聯起來,所以生成了“點擊按鈕后主窗口關閉”的效果。

    Qt QLabel文本框的使用

    QLabel 是 Qt 幫我們寫好的一個控件類,間接繼承自 QWidget 類,它的繼承關系如下:

    QLabel -> QFrame -> QWidget

    從字面上理解,QLabel 可以解釋為“Qt 的 Label”,即 Qt 提供給我們的一種文本控件,它的基礎功能是顯示一串文本。例如,下圖就是一個普通的文本框:

    圖 1 QLabel控件

    除了顯示一串文本外,QLabel 控件上還可以放置圖片、超鏈接、動畫等內容。例如:

    圖 2 QLabel放置圖片和超鏈接文字

    本質上,每個文本框都是 QLabel 類的一個實例對象。QLabel 類提供了兩個構造函數,分別是:

    QLabel(QWidget *parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags())

    QLabel(const QString &text, QWidget *parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags())

    各個參數的含義分別是:

    text 參數用于指定文本框中顯示的文字;

    parent 參數用于指定文本框的父窗口;

    WindowFlags 是一種枚舉類型,f 參數用來設置文本框的一些系統屬性和外觀屬性,默認值為 Qt::Widget,表示當不指定父窗口時,文本框將作為一個獨立窗口(如圖 1、2 所示),反之則作為父窗口中的一個控件。f 參數的可選值有很多,比如 Qt::Window 表示文本框將作為一個獨立的窗口,它自帶邊框和標題欄,Qt::ToolTip 表示文本框將作為一個提示窗口,不帶邊框和標題欄等等,這里不再一一列舉。

    需要注意的是,第一個構造函數中的 parent 和 f 參數都有默認值,因此 QLabel 類還隱含了一個默認構造函數。也就是說,創建 QLable 對象時可以不傳遞任何參數,或者只給 txt 參數傳遞一個字符串,就可以成功創建一個文本框。通常情況下,我們會給 text 和 parent 參數傳遞相應的值,即在創建文本框的同時指定文本內容和父窗口。

    QLabel文本框的使用

    QLabel 類本身提供有很多屬性和方法,它還從父類繼承了很多屬性和方法。下表給大家羅列了 QLabel 類常用的一些屬性和方法:

    屬 性

    含 義

    alignment

    保存 QLabel 控件中內容的對齊方式,默認情況下,QLabel 控件中的內容保持左對齊和垂直居中。 該屬性的值可以通過調用 alignment() 方法獲得,可以借助 setAlignment() 方法修改。

    text

    保存 QLabel 控件中的文本,如果 QLabel 控件中沒有文本,則 text 的值為空字符串, 該屬性的值可以通過 text() 方法獲得,可以借助 setText() 方法修改。

    pixmap

    保存 QLabel 控件內顯示的圖片,如果控件內沒有設置圖片,pixmap 的值為 0。 該屬性的值可以通過調用 pixmap() 方法獲得,可以借助 setPixmap() 方法修改。

    selectedText

    保存 QLabel 控件中被選擇了的文本,當沒有文本被選擇時,selectedText 的值為空字符串。 該屬性的值可以通過調用 selectedText() 方法獲得。

    hasSelectedText

    判斷用戶是否選擇了 QLabel 控件內的部分文本,如果是則返回 true,反之則返回 false。默認情況下,該屬性的值為 false。

    indent

    保存 QLabel 控件內文本的縮進量,文本的縮進方向和 alignment 屬性的值有關。 該屬性的值可以通過調用 indent() 方法獲得,可以借助 setIndent() 方法修改。

    margin

    保存 QLabel 控件中內容與邊框之間的距離(邊距),margin 的默認值為 0。 該屬性的值可以通過調用 margin() 方法獲得,可以借助 setMargin() 方法修改。

    wordWrap

    保存 QLabel 控件內文本的換行策略。當該屬性的值為 true 時,控件內的文本會在必要時自動換行。默認情況下,控件內的文本是禁止自動換行的。 該屬性的值可以通過 wordWrap() 方法獲得,可以借助 setWordWrap() 方法修改。

    除了上表中提到了獲取和修改屬性值得成員方法外,下表給大家羅列了一些常用的操作 QLabel 控件的成員方法,它們有些定義在 QLabel 類內,有些是通過繼承父類得到的:

    成員方法

    功 能

    hide()

    隱藏文本框。

    clear()

    清空 QLabel 控件內所有顯示的內容。

    setToolTip(QString)

    設置信息提示,當用戶的鼠標放在QLabel 文本框上時會自動跳出文字。

    setToolTipDuration(int)

    設置提示信息出現的時間,單位是毫秒。

    setStyleSheet(QString)

    設置 QLabel 文本框的樣式。

    setGeometry(int x, int y, int w, int h)

    設置 QLabel 文本框的位置 (x, y) 以及尺寸 (w, h)。

    QLabel文本框的信號和槽

    QLabel 控件只用來顯示文本、圖像等內容,很好與用戶交互。但是,當 QLabel 控件內包含超鏈接內容時,可以使用 QLabel 類提供的兩個信號函數:

    信號函數

    功 能

    linkActivated(const QString &link)

    用戶點擊超鏈接時觸發,link 參數用于向槽函數傳輸超鏈接的 URL。

    linkHovered(const QString &link)

    用戶的鼠標懸停到超鏈接位置時觸發,link 參數用于向槽函數傳輸超鏈接的 URL。

    QLabel 控件提供了很多槽函數,如下表所示:

    槽函數

    功 能

    clear()

    清空 QLabel 控件內所有的內容。

    setMovie(QMovie *movie)

    清空 QLabel 控件內所有的內容,改為顯示指定的 movie 動畫。

    setNum(int num)

    清空 QLabel 控件內所有的內容,改為顯示 num 整數的值。

    setNum(double num)

    清空 QLabel 控件內所有的內容,改為顯示 num 小數的值。

    setPicture(const QPicture &picture)

    清空 QLabel 控件內所有的內容,改為顯示經 QPicture 類處理的圖像。

    setPixmap(const QPixmap &)

    清空 QLabel 控件內所有的內容,改為顯示經 QPixmap 類處理的圖像。

    setText(const QString &)

    清空 QLabel 控件內所有的內容,改為顯示指定的文本。

    除了表 2、3 羅列的這些信號和槽函數外,QLabel 類還從父類處繼承了一些信號和槽函數,這里不再一一羅列。

    實例演示QLabel文本框的用法

    接下來通過一個實例,給大家演示 QLabel 控件中一些屬性和方法的用法。

    #include <QApplication>
    #include <QLabel>
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        //創建一個文本框
        QLabel lab;
        //設置文本框內容居中顯示
        lab.setAlignment(Qt::AlignCenter);
        //設置文本框的坐標和尺寸
        lab.setGeometry(100,100,400,400);
        //設置文本框的外觀,包括字體的大小和顏色、按鈕的背景色
        lab.setStyleSheet("QLabel{font:30px;color:red;background-color:rgb(f9,f9,f9);}");
        //設置文本框要顯示超鏈接內容
        lab.setText("<a href=\"http://www.baidu.net\">老舅");
        //當用戶鼠標位于文本框上時,顯示提示內容
        lab.setToolTip("點擊超鏈接顯示URL");
        //提示內容顯示 1 秒
        lab.setToolTipDuration(1000);
        //為文本框設置信號和槽,當用戶點擊超鏈接時,將文本框內容改為超鏈接的 URL
        QObject::connect(&lab,&QLabel::linkActivated,&lab,&QLabel::setText);
        //程序運行后,文本框顯示
        lab.show();
        return a.exec();
    }
    

    執行結果如下圖所示,用戶最先看到的是圖 3a),當用戶鼠標移動到文本框區域內時,會提示“點擊超鏈接顯示URL”,提示時間為 1 秒。當用戶點擊“老舅”時會觸發 linkActivated() 信號函數,該函數會調用 setText() 函數,將文本框中顯示的“老舅”改為“http://www.baidu.net”,字體顏色為紅色,如圖 3b) 所示。

    圖 3 程序運行結果

    有關 QLabel 類提供的更多屬性和方法,后續章節用到時會做詳細地講解,您也可以借助 Qt Creator 提供的 Qt 幫助手冊自行查看 QLabel 類提供的成員。

    Qt QPushButton按鈕用法詳解

    按鈕是 GUI 開發中最常用到的一種控件,作為一款著名的 GUI 開發框架,Qt 提供了很多種按鈕,比如 QPushButton(普通按鈕)、QRadioButton(單選按鈕)、QToolButton(工具欄按鈕)等。

    QPushButton 是實際開發中最常使用的一種按鈕,本節就給大家詳細講解它的用法。

    QPushButton按鈕的創建

    QPushButton 類間接繼承自 QWidget 類,它的繼承關系如下:

    QPushButton -> QAbstractButton -> QWidget

    QAbstractButton 類是所有按鈕控件類的基類,包含很多通用的按鈕功能。

    QPushButton 類專門用來創建可按壓的按鈕,如圖 1 所示。

    圖 1 QPushButton 按鈕

    QPushButton 按鈕上除了可以放置一串文本,文本左側還可以放置圖標,必要時還可以在按鈕上放置圖片。QPushButton 按鈕可以作為一個獨立的窗口,但實際開發中很少這樣用,通常的用法是像圖 1 這樣將按鈕內嵌到某個窗口中,作為一個子控件和其它控件搭配使用。

    QPushButton 類提供了 3 個構造函數,分別是:

    QPushButton(QWidget *parent = Q_NULLPTR)

    QPushButton(const QString &text, QWidget *parent = Q_NULLPTR)

    QPushButton(const QIcon &icon, const QString &text, QWidget *parent = Q_NULLPTR)

    parent 參數用于指定父窗口;text 參數用于設置按鈕上要顯示的文字;icon 參數用于設置按鈕上要顯示的圖標。

    注意,第一個構造函數的 parent 參數附有默認值,所以 QPushButton 類還隱含著一個默認構造函數。也就是說,實例化 QPushButton 類對象時可以不傳遞任何參數。

    QPushButton按鈕的使用

    QPushButton 類提供了很多實用的屬性和方法,它還從父類繼承了很多屬性和方法。下表給大家羅列了一些比較常用的屬性和方法:

    屬 性

    含 義

    text

    保存按鈕上要顯示的文字。 該屬性的值可以通過 text() 方法獲取,也可以通過 setText(const QString &text) 方法修改。

    icon

    保存按鈕左側要顯示的圖標。 該屬性的值可以通過 icon() 方法獲取,也可以通過 setIcon(const QIcon &icon) 方法修改。

    iconsize

    保存按鈕左側圖標的尺寸。 該屬性的值可以通過 iconSize() 方法獲取,也可以通過 setIconSize(const QSize &size) 方法修改。

    size

    保存按鈕的尺寸。 該屬性的值可以通過 size() 方法獲取,也可以通過 resize(int w, int h) 或者 resize(const QSize &) 方法修改。

    font

    保存按鈕上文字的字體和大小。 該屬性的值可以通過 font() 方法獲取,也可以通過 setFont(const QFont &) 方法修改。

    flat

    初始狀態下,按鈕是否顯示邊框。flat 屬性的默認值為 flase,表示按鈕帶有邊框。 該屬性的值可以通過 isFlat() 方法獲取,也可以通過 setFlat(bool) 方法修改。

    enabled

    指定按鈕是否可以被按下。 該屬性的默認值為 true,表示按鈕可以被按下,即按鈕處于啟用狀態。當該屬性的值為 false 時,按鈕將不能被點擊,按鈕處于禁用狀態。 該屬性的值可以通過 isEnabled() 方法獲取,也可以通過 setEnabled(bool) 方法進行修改。

    autoDefault

    當用戶按下 Enter 回車鍵時,是否觸發點擊按鈕的事件。 當按鈕的父窗口為 QDialog 窗口時,該屬性的值為 true;其它情況下,該屬性的默認值為 false。 該屬性的值可以通過 autoFault() 方法獲取,也可以通過 setAutoFault(bool) 方法修改。

    除了表 1 中羅列的獲取、修改屬性值的方法外,QPushButton 類常用的成員方法還有:

    方 法

    功 能

    move(int x, int y)

    手動指定按鈕位于父窗口中的位置。

    setStyleSheet(const QString &styleSheet)

    自定義按鈕的樣式,包括按鈕上文字或圖片的顯示效果,按鈕的形狀等等。

    setGeometry(int x, int y, int w, int h)

    同時指定按鈕的尺寸和位置。

    adjustSize()

    根據按鈕上要顯示的內容,自動調整按鈕的大小。

    setDisabled(bool disable)

    指定按鈕是否可以被按下。當 disable 值為 true 時,表示按鈕不能被按下,即禁用按鈕的功能。

    QPushButton按鈕的信號和槽

    GUI 程序中,按鈕的主要任務是完成和用戶之間的交互,下表羅列了 QPushButton 類常用的信號函數和槽函數:

    信號函數

    功 能

    clicked() clicked(bool checked = false)

    用戶點擊按鈕并釋放(或者按下按鈕對應的快捷鍵)后,觸發此信號。

    pressed()

    用戶按下按鈕時會觸發此信號。

    released()

    用戶松開按鈕時會觸發此信號。

    槽函數

    功 能

    click()

    單擊指定的按鈕。

    setIconSize()

    重新設置按鈕上圖片的尺寸。

    hide()

    隱藏按鈕控件。

    setMenu(QMenu *menu)

    彈出與按鈕關聯的菜單。

    實例演示QPushButton按鈕用法

    接下來通過一個實例,給大家演示 QPushButton 按鈕的用法:

    #include <QApplication>
    #include <QWidget>
    #include <QPushButton>
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        QWidget widget;
        //設置 widget 窗口的標題
        widget.setWindowTitle("QWidget窗口");
        //創建一個按鈕,并內嵌到 widget 窗口中
        QPushButton but("QPushButton按鈕",&widget);
        //按鈕的位置位于距 widget 窗口左上角 (100,100) 的位置
        but.move(100,100);
        //設置按鈕上文字的大小。
        but.setStyleSheet("QPushButton{font:20px;}");
        //調整按鈕的尺寸
        but.resize(200,200);
        //建立信息和槽,當用戶點擊并釋放按鈕后,該按鈕隱藏。
        QObject::connect(&but,&QPushButton::clicked,&but,&QPushButton::hide);
        widget.show();
        return a.exec();
    }
    

    將程序復制到 main.cpp 文件中,運行結果為:

    圖 2 運行結果

    Qt QLineEdit單行輸入框用法詳解

    QLineEdit 是 Qt 提供的一個控件類,它直接繼承自 QWdiget 類,專門用來創建單行輸入框,如下圖所示:

    圖 1 單行文本輸入框

    實際開發中,我們經常用到 QLineEdit 輸入框,比如接收用戶輸入的個人信息、賬戶信息、角色名稱等,就可以用 QLineEdit 實現。

    【文章福利】:Qt開發學習資料包、Qt面試題文檔、項目視頻、學習路線,包括(Qt C++基礎,數據庫編程,Qt項目實戰、Qt框架、QML、Opencv、qt線程等等),免費分享,有需要的可以加君羊領取哦!~學習交流君羊937552610點擊加入領取資料

    QLineEdit單行輸入框的創建

    每個單行輸入框都是 QLineEdit 類的一個實例對象,QLineEdit 類提供有兩個構造函數,分別是:

    QLineEdit(QWidget *parent = Q_NULLPTR)

    QLineEdit(const QString &contents, QWidget *parent = Q_NULLPTR)

    contents 參數用于指定輸入框中的文本內容;parent 參數用于指定新建輸入框控件的父窗口,新建輸入框將會內嵌到父窗口上,作為父窗口的一個子控件。當然,我們也可以不指定父窗口,那么新建的輸入框就會作為獨立的窗口。

    在 QLineEdit 輸入框中,用戶可以直接輸入一行文本,也可以粘貼一行文本,還可以修改輸入框內的文本。某些實際場景中,QLineEdit 輸入框還可以對用戶輸入的內容加以限定,比如:

    限定文本的長度,例如用戶最多可以輸入 20 個字符;

    輸入文本的格式,例如用戶輸入出生日期時,必須按照“yy-mm-dd”的格式輸入;

    輸入的文本內容,例如當前輸入框僅允許用戶輸入數字,或者只允許用戶輸入英文字符。

    QLineEdit單行輸入框的使用

    QLineEdit 類的內部提供了很多實用的屬性和方法,同時還從 QWidget 父類處繼承了一些屬性和方法。

    下表列出了 QLineEdit 類對象經常調用的一些屬性以及它們各自的含義:

    屬 性

    含 義

    text

    保存輸入框中的文本。 該屬性的值可以通過 text() 方法獲取,也可以通過 setText(const QString &) 方法修改。

    maxLength

    設置輸入框中最多可以放置的文本長度。當文本長度超出最大限度后,超出部分將被丟棄。 默認情況下,maxLength 的值為 32767。該屬性的值可以通過 maxLength() 函數獲得,也可以通過 setMaxLength(int) 方法修改。

    placeholderText

    設置提示信息,例如當用戶未選中輸入框時,輸入框中顯示“請輸入…”,而用戶選中輸入框時,“請輸入…” 隨之消失。 該屬性的值可以通過 placeholderText() 方法獲取,也可以通過 setPlaceholderText(const QString &) 方法修改。

    clearButtonEnabled

    當輸入框中有文本時,輸入框的右側可以顯示一個“一鍵清除”按鈕。該屬性的默認值為 false,即輸入框中不會自動顯示清除按鈕。 該屬性的值可以通過 isClearButtonEnabled() 方法獲取,也可以通過 setClearButtonEnabled(bool enable) 方法修改。

    echoMode

    設定輸入框中文本的顯示樣式,該屬性的可選值有以下幾個:QLineEdit::Normal:正常顯示所輸入的字符,此為默認選項。QLineEdit::NoEcho:不顯示任何輸入的字符,常用于密碼類型的輸入,且長度保密QLineEdit::Password:顯示與平臺相關的密碼掩飾字符,而不是實際輸入的字符。當用戶重新點擊輸入框時,可以緊接著之前的文本繼續輸入。QLineEdit::PasswordEchoOnEdit:編輯時正常顯示輸入的字符,編輯完成后改為用密碼掩飾字符顯示。當用戶重新點擊輸入框時,不能緊接著之前的文本繼續輸入。 該屬性的是可以通過 echoMode() 方法獲取,也可以通過 setEchoMode(EchoMode) 方法修改。

    frame

    控制輸入框的邊框。默認情況下,輸入框是帶有邊框的。 該屬性的值可以通過 hasFrame() 方法獲取,也可以通過 setFrame(bool) 方法修改。

    除了上表提到的獲取和修改屬性值的方法外,QLineEdit 類還提供了一些功能實用的方法,例如:

    成員方法

    功 能

    move(int x, int y)

    指定輸入框位于父窗口中的位置。

    setValidator(const QValidator *v)

    限制輸入框中的文本內容,比如輸入框只包含整數。

    setReadOnly(bool)

    設置輸入框是否進入只讀狀態。在只讀狀態下,用戶仍可以采用粘貼、拖拽的方式向輸入框中放置文本,但無法進行編輯。

    setAlignent(Qt::Alignment flag)

    設置輸入框中輸入文本的位置。

    QLineEdit單行輸入框的信號和槽

    QLineEdit 類提供了幾個信號函數,分別對應用戶的幾種輸入狀態。

    信號函數

    功 能

    textEdited(const QString &text)

    當用戶編輯輸入框中的文本時,此信號就會觸發,text 參數即為用戶新編輯的文本。 注意,當程序中試圖通過 setText() 方法修改輸入框中的文本時,不會觸發此信號函數。

    textChanged(const QString &text)

    只要輸入框中的文本內容發生變化,就會觸發此信息。

    returnPressed()

    用戶按下回車鍵時,會觸發此信號。

    editingFinished()

    用戶按下回車鍵,或者鼠標點擊輸入框外的其它位置時,會觸發此信號。

    QLineEdit 類常用的槽函數有以下幾個:

    槽函數

    功 能

    clear()

    清空文本框中的內容。

    setText(const QString &)

    重新指定文本框中的內容。

    QLineEdit單行輸入框的用法示例

    下面的實例給大家演示了 QLineEdit 單行輸入框控件的基本用法,同時還演示了幾個成員方法的用法。

    #include <QApplication>
    #include <QWidget>
    #include <QLineEdit>
    using namespace std;
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        //創建一個窗口,作為輸入框的父窗口
        QWidget widget;
        //設置窗口的標題
        widget.setWindowTitle("QWidget窗口");
       
        //接下來,分別創建兩個輸入框,用于讓用戶分別輸入賬號和密碼
        //創建賬號輸入框
        QLineEdit lineEdit(&widget);
        //指定輸入框位于父窗口中的位置
        lineEdit.move(100,100);
        //設置提示信息
        lineEdit.setPlaceholderText("請輸入賬號...");
        //讓輸入框顯示“一鍵清除”按鈕
        lineEdit.setClearButtonEnabled(true);
       
        //創建密碼輸入框
        QLineEdit lineEditPass(&widget);
        lineEditPass.setPlaceholderText("請輸入密碼...");
        lineEditPass.move(100,150);
        //指定文本顯示方式,保護用戶賬號安全
        lineEditPass.setEchoMode(QLineEdit::Password);
       
        //指定窗口的尺寸和顯示文字的大小
        widget.resize(500,300);
        widget.setFont(QFont("宋體",16));
        widget.show();
        return a.exec();
    }
    

    運行結果為:

    圖 2 運行結果

    Qt QListWidget列表框用法詳解

    很多應用程序中需要以列表的形式向用戶展示數據(資源),比如 Windows 操作系統會以列表的方式展示很多張桌面背景圖(如圖 1a) 所示),再比如很多音樂播放器中以列表的形式展示音樂資源,用戶可以選擇自己喜歡的音樂(如圖 1b) 所示)。

    圖 1 常見的列表窗口

    使用 Qt 框架開發 GUI 程序,如果需要以列表的方法展示數據,可以優先考慮用 QListWidget 類實現。

    QListWidget列表框的創建

    QListWidget 是 Qt 提供的控件類,專門用來創建列表。QListWidget 類的繼承關系如下:

    QListWidget -> QListView -> QAbstractItemView -> QAbstractScrollArea -> QFrame -> QWidget

    這里著重介紹一下 QListView 類,它也可以用來創建列表。對于初學者來說,我強烈建議先學習 QListWidget,它是“簡易版”的 QListView,創建和使用列表的方式更簡單、門檻更低,對初學者更友好。當然,QListWidget 只能創建結構簡單的列表,如果要制作復雜的列表,應優先考慮 QListView,因為它的功能更強大,很多 QListWidget 難以實現的功能,QListView 都能實現。

    通過實例化 QListWidget 類,可以很輕松地創建一個列表。QListWidget 類只提供了 1 個構造函數:

    QListWidget(QWidget *parent = Q_NULLPTR)

    parent 參數用來指定新建列表的父窗口,該參數的默認值是 Q_NULLPTR,表示新建控件沒有父窗口。

    語法層面上分析,可以不為 QListWidget 列表指定父窗口,那么它將作為一個獨立的窗口。但實際開發中,通常會為 QListWidget 列表指定一個父窗口(例如 QWidget 窗口),它將作為父窗口中的一個子控件,和窗口中的其它控件一起搭配使用。

    QListWidgetItem列表項

    QListWidget 列表控件可以顯示多份數據,每份數據習慣稱為列表項(簡稱項),每個列表項都是 QListWidgetItem 類的實例對象。也就是說,QListWidget 中有多少個列表項,就有多少個 QListWidgetItem 類對象。

    默認情況下,QListWidget 中每個列表項獨自占用一行,每個列表項中可以包含文字、圖標等內容。實際開發中,我們還可以將指定的窗口或者控件放置到列表項中顯示,例如 QWidget 窗口、QLabel 文本框、QPushButton 按鈕、QLineEdit 輸入框等。

    借助 QListWidgetItem 類,可以輕松管理 QListWidget 中的每個列表項,包括:

    借助 QListWidgetItemo 類提供的 setIcon()、setText() 等方法,可以輕松地指定每個列表項要包含的內容;

    借助 QListWidgetItemo 類提供的 setFont()、setBackground() 等方法,可以輕松地設置每個列表項的外觀(文字大小、列表項背景等)。

    當然,QListWidgetItem 類還提供有很多其它的成員方法,這里不再一一羅列。

    QListWidget列表框的使用

    對于剛剛創建好的 QListWidget 類對象,不包含任何 QListWidgetItem 類對象,就是一個空列表。借助 QListWidget 類以及父類提供的屬性和方法,我們可以對新建列表執行多種操作。

    下表給大家羅列了一些 QListWidget 類常用的屬性和方法:

    屬性名或方法名

    功 能(含 義)

    count 屬性

    保存當前列表中含有的列表項的總數。 該屬性的值可以通過 count() 方法獲取。

    currentRow 屬性

    保存當前選擇的列表項所在的行數。 該屬性的值可以通過 currentRow() 方法獲取,也可以通過 setCurrentRow(int row) 方法修改當前選擇的列表項。

    sortingEnabled 屬性

    決定當前 QlistWidget 列表是否開發排序功能,默認值為 false,即不開啟排序功能。 該屬性的是可以通過 isSortingEnabled() 方法獲取,可以通過 setSortingEnabled(bool enable) 方法進行修改。

    SelectionMode 屬性

    指明當前列表中是否可以同時選擇多個列表項,或者是否只能連續選擇多個列表項。 該屬性是枚舉類型,可選值有 5 個:QAbstractItemView::SingleSelection:用戶最多只能選擇一個列表項。QAbstractItemView::ContiguousSelection:用戶按住 Shift 鍵,可以連續選擇多個列表項。QAbstractItemView::ExtendedSelection:用戶按住 Ctrl 鍵,可以選中多個列表項。當用戶按住 Shift 鍵,也可以連續選擇多個列表項。QAbstractItemView::MultiSelection:用戶可以選擇多個列表項。QAbstractItemView::NoSelection:用戶無法選擇任何列表項。 該屬性的值可以通過 selectionMode() 方法獲取,也可以通過 setSelectionMode(QAbstractItemView::SelectionMode mode) 方法進行修改。

    ViewMode 屬性

    指定 QListWidget 是按行顯示數據(如圖 1b) ),還是分列顯示數據(如圖 1a) )。 該屬性是枚舉類型,可選值有 2 個:QListView::ListMode:一行一行地顯示列表項,默認情況下,各個列表項不能拖動。QListView::IconMode:分列顯示列表項,默認情況下,各個列表項可以拖動。 該屬性的值可以通過 viewMode() 方法獲取,也可以通過 setViewMode(ViewMode mode) 方法進行修改。

    void addItem ( const QString & label ) void addItem ( QListWidgetItem * item ) void addItems ( const QStringList & labels )

    向 QListWidget 列表的尾部添加指定項,可以是一個文本(label)、一個列表項(item),還可以一次性添加多個文本(labels)。

    void QListWidget::setItemWidget(QListWidgetItem *item, QWidget *widget)

    將指定的 widget 窗口添加到 item 列表項中。

    currentItem()

    返回當前選中的列表項。

    removeItemWidget(QListWidgetItem *item)

    刪除指定的 item 列表項。

    sortItems(Qt::SortOrder order = Qt::AscendingOrder)

    默認將所有列表項按照升序排序,通過指定參數為 Qt::DescendingOrder,可以進行降序排序。

    takeItem(int row)

    返回位于 row 行的列表項。

    selectedItems()

    返回當前被選擇的所有列表項。

    QListWidget列表框的信號和槽

    對于給定的 QlistWidget 列表,用戶可以選中其中的一個或者某些列表項,甚至還可以修改列表項中的內容。QListWidget 類具有很多信號和槽信息,可以捕捉用戶的很多動作,還可以針對用戶的動作做出適當地響應。

    下表給大家羅列了一些常用的信號和槽函數:

    信號函數

    功 能

    itemClicked(QListWidgetItem *item)

    用戶點擊某個列表項時會觸發此信號函數,item 參數指的就是被用戶點擊的列表項。

    itemDoubleClicked(QListWidgetItem *item)

    用戶雙擊某個列表項時會觸發此信號函數,item 參數指的就是被用戶雙擊的列表項。

    itemPressed(QListWidgetItem *item)

    鼠標按下某個列表項時會觸發此信號函數,item 參數指的就是被鼠標按下的列表項,

    itemSelectionChanged()

    當選擇的列表項發生變化時會觸發此信號函數。

    currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)

    當前列表項發生變化時會觸發此信號函數,current 參數指的是新選擇的列表項;previous 參數指的是先前選擇的列表項。

    槽函數

    功 能

    clear()

    刪除列表中的所有列表項。

    scrollToItem(const QListWidgetItem *item, QAbstractItemView::ScrollHint hint = EnsureVisible)

    用 hint 參數指定的滑動方式,讓用戶看到指定的 item 列表項。

    selectAll()

    選擇所有的列表項。

    scrollToBottom() scrollToTop()

    分別將列表滑動到底部和頂部。

    實例演示QListWidget列表框的用法

    接下來,我們親自制作一個 QListWidget 列表:

    //main.cpp#include <QApplication>#include <QWidget>#include <QListWidget>#include <QLabel>#include <QListWidgetItem>using //main.cpp
    #include <QApplication>
    #include <QWidget>
    #include <QListWidget>
    #include <QLabel>
    #include <QListWidgetItem>
    using namespace std;
    class QMyLabel:public QLabel{
        Q_OBJECT
    public slots:
        void rsetText(QListWidgetItem *item);
    };
    void QMyLabel::rsetText(QListWidgetItem *item){
        this->setText(item->text());
    }
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        //創建一個窗口,作為輸入框的父窗口
        QWidget widget;
        //設置窗口的標題
        widget.setWindowTitle("QWidget窗口");
        widget.resize(500,500);
        QListWidget listWidget(&widget);
        listWidget.resize(500,400);
        listWidget.setFont(QFont("宋體",14));
        listWidget.addItem("老舅");
        listWidget.addItem("http://www.baidu.net");
        listWidget.addItem(new QListWidgetItem("Qt教程"));
        QMyLabel print;
        print.setText("選中內容");
        print.setParent(&widget);
        print.resize(500,100);
        print.move(0,400);
        print.setAlignment(Qt::AlignCenter);
        QObject::connect(&listWidget,&QListWidget::itemClicked,&print,&QMyLabel::rsetText);
        widget.show();
        return a.exec();
    }
    //QMyLabel類的定義應該放到 .h 文件中,本例中將其寫到 main.cpp 中,程序最后需要添加 #include "當前源文件名.moc" 語句,否則無法通過編譯。
    #include "main.moc"
    

    程序中,我們自定義了一個 QMyLabel 類,它繼承自 QLabel 文本框類,因此 QMyLabel 也是一個文本框類。在 QMyLabel 類中,我們自定義了一個 rsetText() 槽函數。

    程序的運行結果為:

    圖 2 QListMidget 控件實際應用

    通過運行動畫可以看到,我們將 QListMidget 和自定義的 QMyLabel 控件合理地分布在 QWidget 窗口上,通過為它們的信號和槽建立連接,使得當點擊列表中的某個列表項時,文本框可以顯示列表項中的文本內容。

    Qt布局管理詳解(5種布局控件)

    實際開發中,一個界面上可能包含十幾個控件,手動調整它們的位置既費時又費力。作為一款成熟的 GUI 框架,Qt 提供了很多擺放控件的輔助工具(又稱布局管理器或者布局控件),它們可以完成兩件事:

    自動調整控件的位置,包括控件之間的間距、對齊等;

    當用戶調整窗口大小時,位于布局管理器內的控件也會隨之調整大小,從而保持整個界面的美觀。

    總之借助布局管理器,我們無需再逐個調整控件的位置和大小,可以將更多的精力放在軟件功能的實現上。

    Qt 共提供了 5 種布局管理器,每種布局管理器對應一個類,分別是 QVBoxLayout(垂直布局)、QHBoxLayout(水平布局)、QGridLayout(網格布局)、QFormLayout(表單布局)和 QStackedLayout(分組布局),它們的繼承關系如下圖所示:

    圖 1 各個布局管理類的繼承關系

    QVBoxLayout垂直布局

    垂直布局指的是將所有控件從上到下(或者從下到上)依次擺放,例如:

    圖 2 QVBoxLayout垂直布局

    圖 2 展示了 4 個 QPushButton 按鈕利用 QVBoxLayout 垂直布局的效果。實際場景中,QVBoxLayout 中還可以放置其它控件,比如 QLabel 文本框、QLineEdit 單行輸入框等。

    程序中使用 QVBoxLayout 布局控件,需提前引入<QVBoxLayout>頭文件。每個 QVBoxLayout 控件本質都是 QVBoxLayout 類的實例對象,該類提供了兩個構造函數,分別是:

    QVBoxLayout()
    QVBoxLayout(QWidget *parent)
    

    創建 QVBoxLayout 控件的同時可以指定父窗口,那么它將作為父窗口中管理其它控件的工具;也可以暫時不指定父窗口,待全部設置完畢后再將其添加到某個窗口中。

    QVBoxLayout 類沒有新增任何成員方法,它只能使用從父類繼承的成員方法,下表給大家羅列了常用的一些:

    成員方法

    功 能

    void QBoxLayout::addWidget(QWidget *widget, int stretch = 0, Qt::Alignment alignment = Qt::Alignment())

    向布局管理器中添加指定的 widget 控件。 默認情況下,stretch 拉伸系數為 0,表示 widget 控件的尺寸為默認值;alignment 是一個枚舉類型參數,默認值也是 0,表示該控件會填滿占用的整個空間。

    void QBoxLayout::addStretch(int stretch = 0)

    添加一個空白行,整個窗口中除了控件占用的區域外,其它區域可以由多個(≥0)空白行分攤,分攤比例取余于各個空白行設置的 stretch 參數的值。 strech 參數的默認值為 0,表示當窗口很小時,空白行可以不占據窗口空間。當窗口中包含多個 strech 值為 0 的空白行時,它們會平分窗口中的空白區域。

    void QBoxLayout::addSpacing(int size)

    添加一個 size 大小的固定間距。

    void QLayout::setMargin(int margin)

    設置布局管理器中所有控件的外邊距,上、下、左、右外邊距的大小都為 margin。默認情況下,所有方向的外邊距為 11 px。

    void QLayout::setContentsMargins(int left, int top, int right, int bottom)

    設置布局管理器中所有控件的外邊距,和 setMargin() 的區別是,此方法可以自定義上、下、左、右外邊距的值。

    void QBoxLayout::setDirection(Direction direction)

    設置布局管理器中控件的布局方向,Direction 是一個枚舉類型,對于 QVBoxLayout 布局管理器,direction 參數的值通常選擇 QBoxLayout::TopToBottom(從上到下依次擺放)或者 QBoxLayout::BottomToTop(從下到上依次擺放)。

    bool QBoxLayout::setStretchFactor(QWidget *widget, int stretch)

    設置布局管理器中某個控件的拉伸系數。

    bool QBoxLayout::setStretchFactor(QLayout *layout, int stretch)

    布局管理器內部可以再放置一個布局管理器,該方法用來設置內部某個布局管理器的拉伸系數。

    舉個簡單的例子:

    #include <QApplication>
    #include <QWidget>
    #include <QLabel>
    #include <QVBoxLayout>
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        //創建主窗口
        QWidget widget;
        widget.setWindowTitle("QVBoxLayout垂直布局");
        //創建垂直布局管理器
        QVBoxLayout *layout=new QVBoxLayout;
        //設置布局管理器中所有控件從下往上依次排列
        layout->setDirection(QBoxLayout::BottomToTop);
       
        //連續創建 3 個文本框,并設置它們的背景和字體大小
        QLabel lab1("Label1");
        lab1.setStyleSheet("QLabel{background:#dddddd;font:20px;}");
        lab1.setAlignment(Qt::AlignCenter);
        QLabel lab2("Label2");
        lab2.setStyleSheet("QLabel{background:#cccccc;font:20px;}");
        lab2.setAlignment(Qt::AlignCenter);
        QLabel lab3("Label3");
        lab3.setStyleSheet("QLabel{background:#ffffff;font:20px;}");
        lab3.setAlignment(Qt::AlignCenter);
       
        //將 3 個文本框和 2 個空白行添加到管理器中,它們的伸縮系數比是 2:1:2:3:3
        layout->addStretch(2);
        layout->addWidget(&lab1,1);
        layout->addWidget(&lab2,2);
        layout->addWidget(&lab3,3);
        layout->addStretch(3);
       
        //將布局管理器添加到 widget 窗口中
        widget.setLayout(layout);
        widget.show();
        return a.exec();
    }
    

    程序中做了以下幾個操作:

    通過調用 setDirection() 方法,將添加到 QVBoxLayout 管理器中的所有控件(包括空白行)按照從下到上的順序依次擺放。舉個例子,由于 lab1 文本框是第二個添加到管理器中的,因此在最終顯示的界面中,lab1 位于倒數第二的位置。

    通過調用 addStrech() 方法,向管理器中先后添加了兩個空白行,它們的伸縮系數分別為 2 和 3,因此 widget 窗口中的空白區域會平均分為 5 份,一個空白行占 3 份,另一個占 2 份。

    通過調用 addWidget() 方法,向管理器中先后添加了 3 個文本框,它們的拉伸系數比為 1:2:3,所以當我們拉伸 widget 窗口時,三個文本框的大?。▽挾龋┏尸F 1:2:3 的關系。

    通過調用 setLayout() 方法,成功地將 layout 布局管理器添加到了 widget 窗口中。當然,也可以在創建 layout 對象時指定 widget 作為它的父窗口,兩種方式是完全等價的。

    執行結果為:

    圖 3 QVBoxLayout 實例演示

    QHBoxLayout水平布局

    水平布局指的是將所有控件從左到右(或者從右到左)依次擺放,例如:

    圖 4 QHBoxLayout水平布局

    使用 QHBoxLayout 水平布局控件,程序中要提前引入<QHBoxLayout>頭文件。QHBoxLayout 和 QVBoxLayout 繼承自同一個類,它們的用法非常相似,比如 QHBoxLayout 類也提供了兩個構造函數:

    QHBoxLayout()
    QHBoxLayout(QWidget *parent)
    

    QHBoxLayout 類也沒有新添任何成員方法,它只能使用從父類繼承的成員方法。因此,表 1 中羅列的所有成員方法也同樣適用于 QHBoxLayout 對象。

    注意,當 QHBoxLayout 對象調用表 1 中的 addStretch() 方法時,表示添加一個空白列。

    舉個簡單的例子:

    #include <QApplication>
    #include <QWidget>
    #include <QLabel>
    #include <QHBoxLayout>
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        //創建主窗口
        QWidget widget;
        widget.setWindowTitle("QHBoxLayout水平布局");
        //創建水平布局管理器
        QHBoxLayout *layout=new QHBoxLayout;
        //設置布局管理器中所有控件的布局方向為從右往左依次排列
        layout->setDirection(QBoxLayout::RightToLeft);
        //連續創建 3 個文本框,并設置它們的背景和字體大小
        QLabel lab1("Label1");
        lab1.setStyleSheet("QLabel{background:#dddddd;font:20px;}");
        lab1.setAlignment(Qt::AlignCenter);
        QLabel lab2("Label2");
        lab2.setStyleSheet("QLabel{background:#cccccc;font:20px;}");
        lab2.setAlignment(Qt::AlignCenter);
        QLabel lab3("Label3");
        lab3.setStyleSheet("QLabel{background:#ffffff;font:20px;}");
        lab3.setAlignment(Qt::AlignCenter);
        //將 3 個文本框和 2 個空白列添加到管理器中,它們的拉伸系數比是 2:1:2:3:3
        layout->addStretch(2);
        layout->addWidget(&lab1,1);
        layout->addWidget(&lab2,2);
        layout->addWidget(&lab3,3);
        layout->addStretch(3);
        //將布局管理器添加到 widget 窗口中
        widget.setLayout(layout);
        widget.show();
        return a.exec();
    }
    

    程序執行結果為:

    圖 5 QHBoxLayout水平布局實例

    圖 5 中,最左側和最右側各添加了一個空白列,它們的伸縮比例為 3:2,即它們的寬度比為 3:2。

    QGridLayout網格布局

    網格布局又稱格柵布局或者表格布局,指的是將一些控件按照行和列排列在窗口上,例如:

    圖 6 QGridLayout網格布局

    QGridLayout 的行標和列標都從 0 開始,例如圖 6 中 one 按鈕的位置為 (0, 0),Four 按鈕的位置為 (2, 0)。我們可以隨意指定 QGridLayout 的行數和列數,各個控件可以隨意擺放,必要時某些位置可以空著不用。

    使用 QGridLayout 網格控件,程序中需引入<QGridLayout>頭文件。每個 QGridLayout 控件都是 QGridLayout 類的一個實例對象,該類提供了兩個構造函數,分別是:

    QGridLayout(QWidget *parent)
    QGridLayout()
    

    QGridLayout 類提供了很多實用的成員方法,常用的如下表所示:

    成員方法

    功 能

    int QGridLayout::rowCount() const

    獲取網格的行數。

    int QGridLayout::columnCount() const

    獲取網格的列數。

    void QGridLayout::addWidget(QWidget *widget, int row, int column, Qt::Alignment alignment = Qt::Alignment())

    將 widget 控件添加到網格中的 (row,column) 位置處,并且可以自定義該控件的對齊方式。

    void QGridLayout::addWidget(QWidget *widget, int fromRow, int fromColumn, int rowSpan, int columnSpan, Qt::Alignment alignment = Qt::Alignment())

    將 widget 控件從 (fromRow, fromColumn) 位置開始,跨 rowSpan 行和 ColumnSpan 列添加到網格中,并且可以自定義該控件的對齊方式。

    void QGridLayout::addLayout(QLayout *layout, int row, int column, Qt::Alignment alignment = Qt::Alignment())

    向網格中的 (row, column) 位置處添加 layout 布局管理器。

    void QGridLayout::addLayout(QLayout *layout, int row, int column, int rowSpan, int columnSpan, Qt::Alignment alignment = Qt::Alignment())

    將 layout 布局管理器從 (row, column) 位置開始,跨 rowSpan 行和 ColumnSpan 列添加到網格中,并且可以自定義該布局控件的對齊方式。

    void QGridLayout::setColumnStretch(int column, int stretch)

    給指定的第 column 列設置伸縮系數。

    void QGridLayout::setRowStretch(int row, int stretch)

    給指定的第 row 行設置伸縮系數。

    void QGridLayout::setColumnMinimumWidth(int column, int minSize)

    設置第 column 列的最小寬度。

    void QGridLayout::setRowMinimumHeight(int row, int minSize)

    設置第 row 行的最小寬度。

    舉個簡單的例子:

    #include <QApplication>
    #include <QWidget>
    #include <QLabel>
    #include <QGridLayout>
    #include <QPushButton>
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        //創建主窗口
        QWidget widget;
        widget.setWindowTitle("QGridLayout網格布局");
        //創建 4 個按鈕和 1 個文本框
        QPushButton *but1 = new QPushButton("but1");
        QPushButton *but2 = new QPushButton("but2");
        QLabel *lab3 = new QLabel("lab");
        lab3->setStyleSheet("QLabel{background:#dddddd;font:20px;}");
        lab3->setAlignment(Qt::AlignCenter);
        QPushButton *but3 = new QPushButton("but3");
        QPushButton *but4 = new QPushButton("but4");
        //創建網格布局控件
        QGridLayout *layout = new QGridLayout;
        //向 layout 中添加控件,并指定各個控件的位置
        layout->addWidget(but1, 0, 0);
        layout->addWidget(but2, 0, 2);
        layout->addWidget(lab3, 1, 0, 3, 3);
        layout->addWidget(but3, 4, 0);
        layout->addWidget(but4, 4, 2);
        //將 layout 添加到 widget 窗口中
        widget.setLayout(layout);
        widget.show();
        return a.exec();
    }
    

    程序運行結果為:

    圖 7 QGridLayout網格布局實例

    圖 7 中,文本框控件從 (1,0) 位置開始,占據了 3 行 3 列的表格空間。

    QFormLayout表單布局

    Qt 提供了很多種輸入框控件,包括 QLineEdit 單行輸入框、QTextEdit 多行輸入框等。通常情況下,每個輸入框的旁邊都會附帶一些文字(又稱標簽),用來提示用戶需要輸入的信息。例如,圖 8 中第一個輸入框的標簽為 “Name”,提示用戶填寫自己的姓名。

    圖 8 QFromLayout表單布局

    生成圖 8 這樣的界面,實現的方法有很多,例如:

    分別創建 3 個 QLabel 控件和 3 個 QLineEdit 控件,手動指定它們的位置;

    在 QHBoxLayout 中嵌套 3 個 QVBoxLayout,又或者在 QVBoxLayout 中嵌套 3 個 QHBoxLayout,然后再添加 3 個 QLabel 控件和 3 個 QLineEdit 控件;

    使用 QGridLayout 創建一個 3 行 2 列的表格,向表格中添加 3 個 QLabel 控件和 3 個 QLineEdit 控件。

    使用 QFormLayout 表單布局控件實現。

    第 1 種方法最大的弊端在于,各個控件的尺寸都是固定的,不會隨著父窗口尺寸的改變而改變。第 2、3、4 種方法都是借助布局控件實現的,各個控件的尺寸可以自動調整,但前兩種方法需要手動設置每一列的 strech 拉伸系數,而第 4 種方式不需要??傊畬τ谏深愃茍D 8 這樣的表單窗口,建議大家使用 QFormLayout 控件,因為使用 QFormLayout 編寫的代碼量最少,開發效率最高。

    QFormLayout 可以容納很多個輸入框以及對應的標簽,并將它們從上到下依次排列在界面上(如圖 8 所示)。大多數情況下,QFormLayout 底層是用 QGridLayout 網格布局管理器實現的,和后者不同的是,QFormLayout 只包含 2 列(不限制行數),且第一列放置標簽,第二列放置輸入框。

    使用 QFormLayout 布局控件之前,程序中應引入<QFormLayout>頭文件。每一個表單布局控件都是 QFormLayout 類的一個實例對象,該類僅提供了一個構造函數:

    QFormLayout(QWidget *parent = Q_NULLPTR)

    下表給大家羅列了操作 QFormLayout 對象常用的一些成員方法:

    成員方法

    功 能

    void QFormLayout::addRow(QWidget *label, QWidget *field)

    將指定的 field 控件和存儲標簽的 label 控件添加到表單控件中的末尾。

    void QFormLayout::addRow(const QString &labelText, QWidget *field)

    將指定的 field 控件和 labelText 標簽添加到表單控件的末尾。

    void QFormLayout::insertRow(int row, const QString &labelText, QWidget *field)

    將指定的 field 控件和 labelText 標簽插入到表單控件中指定行的位置。

    void QFormLayout::removeRow(int row)

    刪除表單控件中的指定行。

    void QFormLayout::removeRow(QWidget *widget)

    刪除表單控件中 widget 控件所在的行。

    void setRowWrapPolicy(RowWrapPolicy policy)

    設置標簽的顯示格式,默認標簽位于控件的左側。 RowWrapPolicy 是 QFormLayout 中定義的枚舉類型,該類型包含 3 個值:QFormLayout::DontWrapRows:標簽始終在輸入框的左側;QFormLayout::WrapLongRows:根據輸入框的尺寸,標簽可能位于輸入框的左側,也可能位于上方;QFormLayout::WrapAllRows:標簽始終在輸入框的上方;

    void QFormLayout::setSpacing(int spacing)

    將行間距和列間距設置為 spacing。

    舉個簡單的例子:

    #include <QApplication>
    #include <QWidget>
    #include <QLineEdit>
    #include <QFormLayout>
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        //創建主窗口
        QWidget widget;
        widget.setWindowTitle("QFormLayout表單布局");
        //創建 4 個按鈕和 1 個文本框
        QFormLayout* layout = new QFormLayout();
        //設置表單中的標簽都位于控件的上方
        layout->setRowWrapPolicy(QFormLayout::WrapAllRows);
        //添加 3 行輸入框和標簽
        layout->addRow("Name:",new QLineEdit());
        layout->addRow("Email:",new QLineEdit());
        layout->addRow("Adress:",new QLineEdit());
        //設置行間距和列間距為 10
        layout->setSpacing(10);
        //將 layout 表單添加到 widget 窗口中
        widget.setLayout(layout);
        widget.show();
        return a.exec();
    }
    

    程序運行結果為:

    圖 9 QFormLayout表單布局實例

    QStackedLayout分組布局

    QStackedLayout 布局管理器可以容納多個控件或者窗口,但每次只顯示其中的一個。

    舉個簡單的例子,下圖中的界面就使用了 QStackedLayout 布局管理器:

    圖 10 QStackedLayout布局管理器

    整個窗口被一分為二,左側是 QListWidget 列表控件,右側是 QStackedLayout 布局管理器。QStackedLayout 中包含 QPushButonn、QLabel 和 QLineEdit 這 3 個控件,但每次只能 3 個控件中的一個。

    QStackedLayout 自身無法切換當前顯示的控件或窗口,實際應用時通常和 QListWidget 或者 QComboBox 搭配使用。

    使用 QStackedLayout 布局控件,程序中必須先引入<QStackedLayout>頭文件。 每個 QStackedLayout 控件都是 QStackedLayout 類的一個實例對象,該類提供有 3 個構造函數,分別是:

    QStackedLayout()
    QStackedLayout(QWidget *parent)
    QStackedLayout(QLayout *parentLayout)
    

    借助第二個構造函數,我們可以將 QStackedLayout 添加到指定的 parent 窗口中;借助第三個構造函數,我們可以將 QStackedLayout 嵌入到指定的 parentLayout 布局控件中

    本節學習的 5 種布局控件都可以嵌套使用,例如將 QVBoxLayout 放到 QHBoxLayout 內部、將 QGridLayout 放到 QStackedLayout 內部等。

    下表羅列了操作 QStackedLayout 對象常用的一些成員方法:

    成員方法

    功 能

    int QStackedLayout::addWidget(QWidget *widget)

    將 widget 控件添加到 QStackedLayout 控件中。

    int QStackedLayout::insertWidget(int index, QWidget *widget)

    將 widget 控件插入到 QStackedLayout 控件指定的位置處。

    信號函數

    功 能

    void QStackedLayout::currentChanged(int index)

    切換當前顯示的控件時,會觸發此信號,index 為顯示的新控件的索引。

    void QStackedLayout::widgetRemoved(int index)

    移除某個控件時,會觸發此信號,index 為被移除控件的索引。

    槽函數

    功 能

    void setCurrentIndex(int index)

    將第 index 個控件作為要顯示的控件。

    void QStackedLayout::setCurrentWidget(QWidget *widget)

    設置 widget 作為當前要實現的控件。注意,必須保證 widget 存儲在 QStackedLayout 控件中。

    這里我們以圖 10 所示的窗口為例,實現代碼如下:

    #include <QApplication>
    #include <QWidget>
    #include <QPushButton>
    #include <QLabel>
    #include <QLineEdit>
    #include <QStackedLayout>
    #include <QListWidget>
    #include <QHBoxLayout>
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        //創建主窗口
        QWidget widget;
        widget.setWindowTitle("QStackedLayout分組布局");
        widget.resize(600,400);
        //向主窗口中添加一個水平布局控件
        QHBoxLayout *layout=new QHBoxLayout;
       
        //創建一個列表
        QListWidget listWidget(&widget);
        listWidget.setMinimumWidth(150);
        listWidget.setFont(QFont("宋體",14));
        listWidget.addItem("QPushButton");
        listWidget.addItem("QLabel");
        listWidget.addItem("QLineEdit");
       
        //新建 3 個窗口,分別放置文本框、按鈕和單行輸入框
        QWidget widget1;
        widget1.setMinimumSize(400,400);
        QPushButton but1("這是一個按鈕",&widget1);
        QWidget widget2;
        widget2.setMinimumSize(400,400);
        QLabel lab1("這是一個文本框",&widget2);
        QWidget widget3;
        widget3.setMinimumSize(400,400);
        QLineEdit edit("這是一個單行輸入框",&widget3);
       
        //創建一個分組布局,將 3 個窗口添加到分組控件中
        QStackedLayout *stackedLayout = new QStackedLayout;
        stackedLayout->addWidget(&widget1);
        stackedLayout->addWidget(&widget2);
        stackedLayout->addWidget(&widget3);
       
        //layout 第一列添加 QListWidget 控件,第二列添加分組布局控件,設置它們的伸縮系數比為 1:4
        layout->addWidget(&listWidget,1);
        layout->addLayout(stackedLayout,4);
        //將 layout 水平布局控件添加到 widget 窗口中
        widget.setLayout(layout);
        widget.show();
        //連接信號和槽,實現當點擊列表中的某一項,切換分組布局管理器顯示的控件
        QObject::connect(&listWidget,&QListWidget::currentRowChanged,stackedLayout,&QStackedLayout::setCurrentIndex);
        return a.exec();
    }
    

    此程序中,我們在 QHBoxLayout 水平布局控件內又放置了一個 QStackedLayout 分組布局控件。感興趣的讀者可以編寫程序,測試其它布局控件之間嵌套的效果。

    Qt pro文件詳解

    默認情況下,每個 Qt 項目都包含一個后綴名為.pro、名稱和項目名相同的文件,我們通常稱它為項目管理文件或者工程管理文件(簡稱 pro 文件)。

    例如,新建一個 Qt 項目,如下圖所示:

    圖 1 項目結構

    該項目的項目名為 Demo,項目中共包含 4 個文件,其中 Demo.pro 就是項目管理文件。

    任何一個 Qt 項目都至少包含一個 pro 文件,此文件負責存儲與當前項目有關的配置信息,比如:

    項目中用到了哪些模塊?

    項目中包含哪些源文件,哪些頭文件,它們的存儲路徑是什么?

    項目使用哪個圖片作為應用程序的圖標?

    項目最終生成的可執行文件的名稱是什么?

    所謂模塊,可以簡單地理解為文件夾或者壓縮包,內部包含多個功能相近的類。作為一款成熟的 GUI 框架,Qt 提供了大量的類,根據這些類的功能,Qt 將它們分成了幾個組,每個組稱為一個模塊。打開 Qt Creator 的幫助界面并搜索“All modules”,可以看到 Qt 的所有模塊。

    一個項目中可能包含上百個源文件,Qt 編譯這些源文件的方法是:先由 qmake 工具根據 pro 文件記錄的配置信息生成相應的 makefile 文件,然后執行 make 命令完成對整個項目的編譯。也就是說,pro 文件存儲的配置信息是用來告知編譯器如何編譯當前項目的,所以一個 Qt 項目要想完美運行,既要保證各個源文件中程序的正確性,還要保證 pro 文件中配置信息的合理性。

    對于一個剛剛創建好的 Qt 項目,pro 文件并不是空的,而是包含一些基本的配置信息。實際開發中,Qt 會自動修改 pro 文件的內容,但有時也需要我們手動修改,例如程序中用到某個第三方庫時,就需要我們手動修改 pro 文件。

    接下來,我們就為大家詳細地講解 pro 文件中各個配置信息的含義,以及如何手動修改 pro 文件。

    pro文件中的配置信息

    在圖 1 所示的 Demo 項目中,雙擊打開 Demo.pro 項目管理文件,會看到如下內容:

    #-------------------------------------------------
    #
    # Project created by QtCreator 2021-08-31T16:05:04
    #
    #-------------------------------------------------
    
    QT += core gui
    
    greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
    
    TARGET = Demo
    TEMPLATE = app
    
    # The following define makes your compiler emit warnings if you use
    # any feature of Qt which as been marked as deprecated (the exact warnings
    # depend on your compiler). Please consult the documentation of the
    # deprecated API in order to know how to port your code away from it.
    DEFINES += QT_DEPRECATED_WARNINGS
    
    # You can also make your code fail to compile if you use deprecated APIs.
    # In order to do so, uncomment the following line.
    # You can also select to disable deprecated APIs only up to a certain version of Qt.
    #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
    
    SOURCES +=
    main.cpp
    mainwindow.cpp
    
    HEADERS +=
    mainwindow.h
    

    以上是 Demo.pro 配置文件中默認包含的內容。其中,#號是注釋符號,除了以#號開頭的注釋內容外,其它內容都是當前項目的配置信息,比如QT += core gui、TARGET = Demo等。

    pro 文件可以存儲上百條配置信息,每條配置信息由三部分構成:

    前半部分是關鍵字,也稱配置項,用來指明配置信息的含義;

    中間用 +=、-=、= 等數學符號連接配置項和它對應的值;

    后半部分是配置項對應的值,一個配置項可以對應多個值,每個值代表不同的含義。

    例如在 QT += core gui中,Qt是配置項,core和gui是該配置項的值,中間用+=符號連接。下表給大家羅列了一些常用的配置項以及它們各自的含義。

    配置項

    含 義

    QT

    指定項目中用到的所有模塊,默認值為 core 和 gui,中間用 += 符號連接。

    greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

    如果 QT 版本大于 4(Qt5 或更高版本),則需要添加 widgets 模塊,該模塊包含所有控件類。

    TARGET

    指定程序成功運行后生成的可執行文件的名稱,中間用 = 符號連接。

    TEMPLATE

    指定如何運行當前程序,默認值為 app,表示當前程序是一個應用程序,可以直接編譯、運行。常用的值還有 lib,表示將當前程序編譯成庫文件。

    DEFINES

    在程序中新定義一個指定的宏,比如 DEFINES += xxx,如同在程序中添加了 #define xxx 語句。

    SOURCES

    指定項目中包含的所有 .cpp 源文件。

    HEADERS

    指定項目中包含的所有 .h 頭文件。

    FORMS

    指定項目中包含的 ui 文件。

    INCLUDEPATH

    指定頭文件的存儲路徑,例如:INCLUDEPATH += /opt/ros/include

    CONFIG

    經常對應的值有:release:以 release 模式編譯程序;debug:以 debug 模式編譯程序;warn_on:編譯器輸出盡可能多的警告;c++11:啟動 C++11 標準支持。例如 CONFIG += c++11。

    根據上表中對各個配置項的講解,您可以很輕松地搞清楚 Demo.pro 文件中各個配置項的含義,這里不再過多贅述。

    上表中,大部分配置項不需要我們手動修改,比如 SOURCES、HEADERS、FORMS 等,當我們添加或者刪除項目中的源文件時,Qt 會自動修改這些配置項。有些配置項需要手動修改,比如 QT 配置項,接下來重點給大家講解 QT 的用法。

    QT配置項

    前面提到,Qt 根據各個類的功能將它們分到不同的模塊,因此程序中要想使用某個類,必須完成兩項準備工作:

    引入包含該類的頭文件,通常情況下,Qt 中每個類的類名和包含它的頭文件的名稱是相同的,比如 QWiget 窗口類位于<QWidget>頭文件中;

    將該類所屬的模塊添加到 pro 項目管理文件中。

    QT用來指明當前項目中用到的所有模塊,它的默認值是 core 和 gui,分別表示引入 Core 模塊和 GUI 模塊:

    Core 模塊包含了 Qt GUI 界面開發的核心功能,其它所有模塊都需要依賴于這個模塊,它是所有 Qt GUI 項目必備的模塊;

    GUI 模塊提供了用于開發 GUI 應用程序的必要的一些類。

    每個新創建的 Qt GUI 項目中,都默認包含 Core 模塊和 GUI 模塊,如果項目中用不到它們,可以使用QT -=刪除。例如,刪除項目中包含的 GUI 模塊,只需在 pro 文件中添加一條配置信息:

    QT -= gui

    除了 Core 和 GUI 模塊外,Qt 還有 SQL(包含操作數據庫相關的類)、Widgets(包含構建界面的所有控件類)、Multimedia(包含提供音頻、視頻等功能的類)等模塊,Qt 項目不會自動包含這些模塊。例如,項目中用到 SQL 模塊中的一些類時,需要在 pro 文件中添加如下配置信息:

    QT += sql

    那么,當程序中用到某個類時,如何知道它屬于哪個模塊呢?很簡單,先將該類所在的頭文件中引入到程序中,然后鼠標選中頭文件并按Fn+F1組合鍵,打開該頭文件的使用手冊后就可以看到它所屬的模塊。以程序中使用 QWidget 窗口類為例,先在程序中添加如下語句:

    #include <QWidget> 

    緊接著,鼠標選中“QWidget”并按Fn+F1組合鍵,打開下圖所示的 QWdiget 類使用手冊,可以看到該類所屬的模塊為 widgets。

    圖 2 查看類所屬的模塊

    Qt自定義信號和槽函數

    實際開發中,如果僅使用 Qt 提供的信號函數和槽函數,會經常遇到信號函數的參數類型和個數無法滿足實際需求、信號函數和槽函數的參數類型不匹配等問題。解決此類問題,最簡單有效的方式就是:自定義場景需要的信號函數和槽函數。

    自定義信號函數

    信號函數指的是符合以下條件的函數:

    定義在某個類中,該類直接或間接繼承自 QObject 類;

    用 signals 關鍵字修飾;

    函數只需要聲明,不需要定義(實現);

    函數的返回值類型為 void,參數的類型和個數不限。

    舉個簡單的例子:

    class MyWidget:public QWidget{
        //Q_OBJECT 是一個宏,添加它才能正常使用 Qt 的信號和槽機制
        Q_OBJECT
    //修飾信號函數的關鍵字
    signals:
        //自定義的信號函數
        void MySignal(QString message);
    };
    

    我們自定義了一個繼承自 QWidget 的 MyWidget 類,QWidget 是 QObject 的子類,所以 MyWidget 間接繼承自 QObject 類。MyWidget 類中自定義了名為 MySignal 的信號函數(可以簡稱 MySignal 信號),它用 signals 關鍵字修飾,沒有返回值,也沒有定義(實現),僅有 1 個參數。

    對于 MySignal() 信號函數,程序中不會直接調用它,而是借助 connect() 連接某個槽函數,實現的語法格式是:

    MyWidget myWidget;
    QObject::connect(&myWidget,&MyWidget::MySignal,信號接收者,槽函數);

    一旦確定了信號接收者和槽函數,當 MySignal 信號發出后,與之相連的槽函數就會執行。那么,程序中如何發出 MySignal 信號呢?

    對于 Qt 提供給我們的信號函數,其底層已經設置好了信號發出的時機,例如按下鼠標時、點擊 Enter 回車鍵時等等。對于自定義的信號,我們需要自己指定信號發出的時機,這就需要用到 emit 關鍵字。emit 中文意思為“發出、射出”,是 Qt 在 C++ 基礎上擴展的一個關鍵字,專門用來發射信號。

    以定義好的 MySignal 信號為例,修改 MyWidget 類為:

    class MyWidget:public QWidget{
        //Q_OBJECT 是一個宏,添加它才能正常使用 Qt 的信號和槽機制
        Q_OBJECT
    //自定義信號函數
    signals:
        void MySignal(QString mess);
    public:
        void emitSignal(){
            emit MySignal(message);
        }
    private:
        QString message;
    };
    

    我們為 MyWidget 類新增了一個 emitSignal() 方法和一個 message 屬性,emitSignal() 方法中的emit MySignal(message);語句就表示發射 MySignal 信號。當程序中執行 emitSingal() 函數時,就會發出 MySignal 信號,message 屬性的值也會隨信號一同發出,對應的槽函數可以接收到 message 的值。

    對于每一個自定義的信號函數,程序中都應該提供發射該信號的方法(函數),而且這樣的方法(函數)可以有多個。

    自定義槽函數

    Qt5 中,槽函數既可以是普通的全局函數、也可以是類的成員函數、靜態成員函數、友元函數、虛函數,還可以用 lambda 表達式表示。

    和信號函數不同,槽函數必須手動定義(實現)。槽函數可以在程序中直接調用,但主要用來響應某個信號。自定義一個槽函數時,需要注意以下幾點:

    槽函數的返回值必須和信號函數相同,由于信號函數的返回值一定是 void,所以槽函數的返回值也必須為 void;

    對于帶參的信號函數,槽函數可以選擇接收所有參數,則參數的類型、順序、個數都必須與信號函數相同;也可以選擇接收前幾個參數,這些參數的類型、順序都必須與信號函數相同;還可以選擇不接受任何參數。

    槽函數的參數個數只能比信號函數少,不能比信號函數多;

    槽函數的參數不能有默認值。

    舉個例子,自定義響應 MySignal 信號的槽函數:

    class MyWidget:public QWidget{
        //Q_OBJECT 是一個宏,添加它才能正常使用 Qt 的信號和槽機制
        Q_OBJECT
    signals:
        void MySignal(QString mess1,QString mess2);
    public:
        void emitSignal(){
            emit MySignal(message1,message2);
        }
        //類的成員函數
        void recSlot1(QString mess){
            qDebug() << "執行 recSlot1() 成員函數,輸出" << mess;
        }
    //指明定義的是槽函數
    public slots:
        void recSlot2(QString mess1,QString mess2){
            qDebug() << "執行 recSlot2() 槽函數,輸出"<< mess1 << " " << mess2;
        }
    public:
        QString message1;
        QString message2;
    };
    //全局函數
    void recSlot3(){
        qDebug() << "執行 recSlot3() 全局函數";
    }
    

    程序中,重點關注 recSlot1()、recSlot2()、recSlot3() 這 3 個函數:

    recSlot1() 是 MyWidget 類內部的 public 成員函數,可以當做槽函數使用;

    recSlot2() 位于 MyWidget 類的內部,修飾它的關鍵字是 public slots。slots 和 emit 一樣,是 Qt 擴展的一個關鍵字,專門用來修飾槽函數。也就是說,recSlot2() 是 MyWidget 類中的槽函數。

    recSlot3() 是全局函數,可以當做槽函數使用。

    slots 關鍵字可以和 public、protected、private 搭配使用,它們的區別是:

    public slots:該關鍵字修飾的槽函數,既可以在當前類及其子類的成員函數中調用,也可以在類外部的其它函數(比如 main() 函數)中調用;

    protected slots:該關鍵字修飾的槽函數,僅允許在當前類及其子類的成員函數內調用,不能在類外部的其它函數內調用;

    private slots:該關鍵字修飾的槽函數,只允許在當前類的成員函數內調用,不能在子類中調用,也不能在類外部的其它函數內調用。

    通常情況下,槽函數使用 public slots 修飾。

    很多讀者會問,既然 public 修飾的成員函數可以當做槽函數,為什么還要提供 slots 關鍵字呢?筆者認為,“兼容舊的 Qt 版本”是其中的一個原因。Qt4 中的槽函數只能是 slots 修飾的類成員函數,Qt5 中取消了這一限制,但考慮到要兼容舊的 Qt 版本,Qt5 保留了舊版本中 connect() 函數的語法格式,也保留了 slots 關鍵字。

    調用 connect() 函數,將 MySignal() 信號函數分別連接 recSlot1()、recSlot2()、recSlot3() 三個槽函數,實現代碼為://類的成員函數作為槽函數QObject::connect(&mywidget,&MyWidget::MySignal,&mywidget,&MyWidget::recSlot1);//信號函數和槽函數相連接QObject::connect(&mywidget,&MyWidget::MySignal,&mywidget,&MyWidget::recSlot2);//全局函數作為槽函數QObject::connect(&mywidget,&MyWidget::MySignal,&recSlot3);
    

    自定義信號和槽的完整實例

    //main.cpp
    #include <QApplication>
    #include <QWidget>
    #include <QDebug>
    class MyWidget:public QWidget{
        //Q_OBJECT 是一個宏,添加它才能正常使用 Qt 的信號和槽機制
        Q_OBJECT
    //信號函數
    signals:
        void MySignal(QString mess1,QString mess2);
    public:
        //發射信號的函數
        void emitSignal(){
            emit MySignal(message1,message2);
        }
        //普通類成員函數
        void recSlot1(QString mess){
            qDebug() << "執行 recSlot1() 成員函數,輸出" << mess;
        }
    //槽函數
    public slots:
        void recSlot2(QString mess1,QString mess2){
            qDebug() << "執行 recSlot2() 槽函數,輸出"<< mess1 << " " << mess2;
        }
    public:
        QString message1;
        QString message2;
    };
    //全局函數
    void recSlot3(){
        qDebug() << "執行 recSlot3() 全局函數";
    }
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        //創建主窗口
        MyWidget mywidget;
        mywidget.message1 = "C老舅";
        mywidget.message2 = "http://www.baidu.net";
        //類的成員函數作為槽函數
        QObject::connect(&mywidget,&MyWidget::MySignal,&mywidget,&MyWidget::recSlot1);
        //信號函數和槽函數相連接
        QObject::connect(&mywidget,&MyWidget::MySignal,&mywidget,&MyWidget::recSlot2);
        //全局函數作為槽函數
        QObject::connect(&mywidget,&MyWidget::MySignal,&recSlot3);
        mywidget.show();
        //發射 Signal 信號
        mywidget.emitSignal();
        return a.exec();
    }
    //MyWidget類的定義應該放到 .h 文件中,本例中將其寫到 main.cpp 中,程序最后需要添加 #include "當前源文件名.moc" 語句,否則無法通過編譯。
    #include "main.moc"
    

    執行程序,會彈出一個 myWidget 空白窗口,同時輸出以下信息:

    執行 recSlot1() 成員函數,輸出 “老舅”

    執行 recSlot2() 槽函數,輸出 “ 老舅” “http://www.baidu.net”

    執行 recSlot3() 全局函數

    Qt QFile文件操作詳解

    很多應用程序都需要具備操作文件的能力,包括對文件內容進行讀/寫、創建和刪除文件等,甚至某些應用程序的誕生純粹是為了操作文件,比如 WPS Office、PDFedit 等。為此,Qt 框架提供了 QFile 類專門用來操作文件。

    QFile文件操作

    QFile 類支持對文件進行讀取、寫入、刪除、重命名、拷貝等操作,它既可以操作文件文件,也可以操作二進制文件。

    使用 QFile 類操作文件之前,程序中需引入<QFile>頭文件。創建 QFile 類的對象,常用的構造函數有:

    QFile::QFile()
    QFile::QFile(const QString &name)

    參數 name 用來指定要操作的目標文件,包含文件的存儲路徑和文件名,存儲路徑可以使用絕對路徑(比如 “D:/Demo/test.txt”)或者相對路徑(比如"./Demo/test.txt"),路徑中的分隔符要用 “/” 表示。

    通常情況下,我們會調用第二個構造函數,直接指明要操作的文件。對于第一個構造函數創建的 QFile 對象,需要再調用 setFileName() 方法指明要操作的文件。

    與 C++ 讀寫文件的規則一樣,使用 QFile 讀寫文件之前必須先打開文件,調用 open() 成員方法即可,常用的語法格式為:

    bool QFile::open(OpenMode mode)

    mode 參數用來指定文件的打開方式,下表羅列了此參數的可選值以及各自的含義:

    打開方式

    含 義

    QIODevice::ReadOnly

    只能對文件進行讀操作

    QIODevice::WriteOnly

    只能對文件進行寫操作,如果目標文件不存在,會自行創建一個新文件。

    QIODevice::ReadWrite

    等價于 ReadOnly | WriteOnly,能對文件進行讀和寫操作。

    QIODevice::Append

    以追加模式打開文件,寫入的數據會追加到文件的末尾(文件原有的內容保留)。

    QIODevice::Truncate

    以重寫模式打開,寫入的數據會將原有數據全部清除。注意,此打開方式不能單獨使用,通常會和 ReadOnly 或 WriteOnly 搭配。

    QIODevice::Text

    讀取文件時,會將行尾結束符(Unix 系統中是 “\n”,Windows 系統中是 “\r\n”)轉換成‘\n’;將數據寫入文件時,會將行尾結束符轉換成本地格式,例如 Win32 平臺上是‘\r\n’。

    根據需要,可以為 mode 參數一次性指定多個值,值和值之間用|分割。比如:

    QIODevice::ReadOnly | QIODevice::Text:表示只允許對文件進行讀操作,讀取文件時,會將行尾結束符轉換為 ‘\n’;

    QIODevice::WriteOnly | QIODevice::Text:表示只允許對文件進行寫操作,將數據寫入文件時,會將行尾結束符轉換為本地格式;

    QIODevice::ReadWrite | QIODevice::Append | QIODevice::Text:表示對文件進行寫操作,寫入的數據會存放到文件的尾部,同時數據中的行尾結束符轉換為本地格式。

    注意,傳遞給 mode 參數的多個值之間不能相互沖突,比如 Append 和 Truncate 不能同時使用。

    如果文件成功打開,open() 函數返回 true,否則返回 false。

    QFile 類提供了很多功能實用的方法,可以快速完成對文件的操作,下表列舉了常用的一些:

    普通成員方法

    功 能

    qint64 QFile::size() const

    獲取當前文件的大小。對于打開的文件,該方法返回文件中可以讀取的字節數。

    bool QIODevice::getChar(char *c)

    從文件中讀取一個字符,并存儲到 c 中。讀取成功時,方法返回 true,否則返回 false。

    bool QIODevice::putChar(char c)

    向文件中寫入字符 c,成功時返回 true,否則返回 false。

    QByteArray QIODevice::read(qint64 maxSize)

    從文件中一次性最多讀取 maxSize 個字節,然后返回讀取到的字節。

    qint64 QIODevice::read(char *data, qint64 maxSize)

    從文件中一次性對多讀取 maxSize 個字節,讀取到的字節存儲到 data 指針指定的內存控件中。該方法返回成功讀取到的字節數。

    QByteArray QIODevice::readAll()

    讀取文件中所有的數據。

    qint64 QIODevice::readLine(char *data, qint64 maxSize)

    每次從文件中讀取一行數據或者讀取最多 maxSize-1 個字節,存儲到 data 中。該方法返回實際讀取到的字節數。

    qint64 QIODevice::write(const char *data, qint64 maxSize)

    向 data 數據一次性最多寫入 maxSize 個字節,該方法返回實際寫入的字節數。

    qint64 QIODevice::write(const char *data)

    將 data 數據寫入文件,該方法返回實際寫入的字節數。

    qint64 QIODevice::write(const QByteArray &byteArray)

    將 byteArray 數組中存儲的字節寫入文件,返回實際寫入的字節數。

    bool QFile::copy(const QString &newName)

    將當前文件的內容拷貝到名為 newName 的文件中,如果成功,方法返回 true,否則返回 false。 copy 方法在執行復制操作之前,會關閉源文件。

    bool QFile::rename(const QString &newName)

    對當前文件進行重命名,新名稱為 newName,成功返回 true,失敗返回 false。

    bool QFile::remove()

    刪除當前文件,成功返回 true,失敗返回 false。

    【實例一】演示了 QFile 類讀寫文本文件的過程。

    #include <QFile>#include <QDebug>int main(int argc, char *argv[]){    //創建 QFile 對象,同時指定要操作的文件    QFile file("D:/demo.txt");    //對文件進行寫操作    if(!file.open(QIODevice::WriteOnly|QIODevice::Text)){        qDebug()<<"文件打開失敗";    }    //向文件中寫入兩行字符串    file.write("老舅\n");    file.write("http://www.baidu.net");    //關閉文件    file.close();    //重新打開文件,對文件進行讀操作    if(!file.open(QIODevice::ReadOnly|QIODevice::Text)){        qDebug()<<"文件打開失敗";    }    //每次都去文件中的一行,然后輸出讀取到的字符串    char * str = new char[100];    qint64 readNum = file.readLine(str,100);    //當讀取出現錯誤(返回 -1)或者讀取到的字符數為 0 時,結束讀取    while((readNum !=0) && (readNum != -1)){        qDebug() << str;        readNum = file.readLine(str,100);    }    file.close();    return 0;}#include <QFile>
    #include <QDebug>
    int main(int argc, char *argv[])
    {
        //創建 QFile 對象,同時指定要操作的文件
        QFile file("D:/demo.txt");
        //對文件進行寫操作
        if(!file.open(QIODevice::WriteOnly|QIODevice::Text)){
            qDebug()<<"文件打開失敗";
        }
        //向文件中寫入兩行字符串
        file.write("老舅\n");
        file.write("http://www.baidu.net");
        //關閉文件
        file.close();
        //重新打開文件,對文件進行讀操作
        if(!file.open(QIODevice::ReadOnly|QIODevice::Text)){
            qDebug()<<"文件打開失敗";
        }
        //每次都去文件中的一行,然后輸出讀取到的字符串
        char * str = new char[100];
        qint64 readNum = file.readLine(str,100);
        //當讀取出現錯誤(返回 -1)或者讀取到的字符數為 0 時,結束讀取
        while((readNum !=0) && (readNum != -1)){
            qDebug() << str;
            readNum = file.readLine(str,100);
        }
        file.close();
        return 0;
    }
    

    執行程序,“老舅” 和 “http://www.baidu.net” 先寫入 D 盤的 demo.txt 文件,然后再從文件中將它們讀取出來。

    【實例二】演示 QFile 讀寫二進制文件的過程。

    #include <QFile>
    #include <QDebug>
    int main(int argc, char *argv[])
    {
        //指定要寫入文件的數據
        qint32 nums[5]={1,2,3,4,5};
        //寫入文件之前,要將數據以二進制方式存儲到字節數組中
        QByteArray byteArr;
        byteArr.resize(sizeof(nums));
        for(int i=0;i<5;i++){
            //借助指針,將每個整數拷貝到字節數組中
            memcpy(byteArr.data()+i*sizeof(qint32),&(nums[i]),sizeof(qint32));
        }
        //將 byteArr 字節數組存儲到文件中
        QFile file("D:/demo.dat");
        file.open(QIODevice::WriteOnly);
        file.write(byteArr);
        file.close();
        //再次打開文件,讀取文件中存儲的二進制數據
        file.open(QIODevice::ReadOnly);
        QByteArray resArr = file.readAll();
        //輸出讀取到的二進制數據
        qDebug()<<"resArr: "<<resArr;
        //將二進制數據轉化為整數
        char* data = resArr.data();
        while(*data){
            qDebug() << *(qint32*)data;
            data += sizeof(qint32);
        }
        return 0;
    }
    

    執行程序,demo.dat 文件中會存儲 {1,2,3,4,5} 這 5 個整數的二進制形式,同時輸出以下內容:

    resArr: “\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00\x05\x00\x00\x00”

    1

    2

    3

    4

    5

    單獨使用 QFile 類讀寫文件的過程既繁瑣又復雜,Qt 提供了兩個輔助類 QTextStream 和 QDataStream,前者用來讀寫文件文件,后者用來讀寫二進制文件,QFile 可以和它們搭配使用,從整體上提高讀寫文件的開發效率。

    QFile+QTextStream

    和單獨使用 QFile 類讀寫文本文件相比,QTextStream 類提供了很多讀寫文件相關的方法,還可以設定寫入到文件中的數據格式,比如對齊方式、寫入數字是否帶前綴等等。

    使用 QTextStream 類之前,程序中要先引入<QTextStream>頭文件。QTextStream 類提供了很多種構造函數,常用的是:

    QTextStream(QIODevice *device)

    QIODevice 是 QFile 的父類,因此在構造 QTextStream 類的對象時,需要傳遞一個 QFile 類的對象。

    下表羅列了 QTextStream 類常用的一些方法:

    成員方法

    功 能

    bool QTextStream::atEnd() const

    判斷是否讀到文件末尾,如果已經達到末尾,返回 true,否則返回 false。

    QString QTextStream::read(qint64 maxlen)

    從文件中讀最多 maxlen 個字符,返回這些字符組成的 QString 字符串。

    QString QTextStream::readAll()

    從文件中讀取所有內容,返回由讀取內容組成的 QString 字符串。

    QString QTextStream::readLine(qint64 maxlen = 0)

    默認讀取一行文本,如果手動指定 maxlen 的值,則最多讀取 maxlen 個字符,并返回讀取內容組成的 QString 字符串。

    void QTextStream::setFieldAlignment(FieldAlignment mode)

    設置對齊方式,通常與 setFieldWidth() 一起使用。

    void QTextStream::setFieldWidth(int width)

    設置每份數據占用的位置寬度為 width。

    QTextStream 類重載了>>輸入運算符和>>輸出運算符,使讀寫文本文件變得更簡單。例如,用 QTextStream 實現【實例一】的程序如下:

    #include <QFile>
    #include <QDebug>
    #include <QString>
    #include <QTextStream>
    int main(int argc, char *argv[])
    {
        //創建 QFile 對象,同時指定要操作的文件
        QFile file("D:/demo.txt");
        //對文件進行寫操作
        if(!file.open(QIODevice::WriteOnly|QIODevice::Text)){
            qDebug()<<"文件打開失敗";
        }
        QTextStream out(&file);
        //向文件中寫入兩行字符串
        out << (QString)"老舅\n" << (QString)"http://www.baidu.net";
        //關閉文件
        file.close();
        //重新打開文件,對文件進行讀操作
        if(!file.open(QIODevice::ReadOnly|QIODevice::Text)){
            qDebug()<<"文件打開失敗";
        }
        QTextStream in(&file);
        //一直讀,直至讀取失敗
        while(!in.atEnd()){
            QString str;
            //從文件中讀取一個字符串
            in >> str;
            qDebug() << str;
        }
        file.close();
        return 0;
    }
    

    和<iostream>類似,QTextStream 類提供了兩種格式化輸出的方法,一種是調用該類的成員方法,例如表 3 中的 setFieldAlignment()、setFieldWidth 等,另一種是調用 QTextStream 類提供的格式描述符,下表羅列了常用的一些:

    描述符

    功能相同的方法

    Qt::hex

    QTextStream::setIntegerBase(16)

    Qt::showbase

    QTextStream::setNumberFlags(numberFlags() | ShowBase)

    Qt::forcesign

    QTextStream::setNumberFlags(numberFlags() | ForceSign)

    Qt::fixed

    QTextStream::setRealNumberNotation(FixedNotation)

    Qt::scientific

    QTextStream::setRealNumberNotation(ScientificNotation)

    Qt::left

    QTextStream::setFieldAlignment(AlignLeft)

    Qt::right

    QTextStream::setFieldAlignment(AlignRight)

    Qt::center

    QTextStream::setFieldAlignment(AlignCenter)

    舉個簡單的例子:

    #include <QFile>
    #include <QDebug>
    #include <QString>
    #include <QTextStream>
    int main(int argc, char *argv[])
    {
        QFile file("D:/demo.txt");
        if(!file.open(QIODevice::WriteOnly|QIODevice::Text)){
            qDebug()<<"文件打開失敗";
        }
        QTextStream out(&file);
        //將 10 的十六進制數寫入文件
        out << hex << 10;
        //設置每份數據占用 10 個字符的位置
        out.setFieldWidth(10);
        //以右對齊的方式寫入 3.14
        out << left << 3.14;
        //后續數據以左對齊的方式寫入文件
        out.setFieldAlignment(QTextStream::AlignRight);
        out << 2.7;
        //關閉文件
        file.close();
        return 0;
    }
    

    程序運行后,demo.txt 存儲的文本內容為:

    a3.14 2.7

    QFile+QDataStream

    QDataStream 類的用法和 QTextStream 非常類似,最主要的區別在于,QDataStream 用于讀寫二進制文件。

    使用 QDataStream 類之前,程序中要引入<QDataStream>頭文件。創建 QDataStream 對象常用的構造函數為:

    QDataStream::QDataStream(QIODevice *d)

    下表羅列了 QDataStream 類常用的成員方法:

    成員方法

    功 能

    bool QDataStream::atEnd() const

    判斷是否讀到文件末尾,如果已經達到末尾,返回 true,否則返回 false。

    QDataStream &QDataStream::readBytes(char *&s, uint &l)

    對于用 writeBytes() 方法寫入文件的 l 和 s,只能使用 readBytes() 方法讀取出來。

    int QDataStream::readRawData(char *s, int len)

    從文件中讀取最多 len 字節的數據到 s 中,返回值表示實際讀取的字節數。注意,調用該方法之前,需要先給 s 參數分配好內存空間。

    void QDataStream::setVersion(int v)

    不同版本的 Qt 中,同名稱的數據類型也可能存在差異,通過調用此方法手動指定版本號,可以確保讀取數據的一致性。

    int QDataStream::skipRawData(int len)

    跳過文件中的 len 個字節,返回實際跳過的字節數。

    QDataStream &QDataStream::writeBytes(const char *s, uint len)

    將長度 len 和 s 一起寫入到文件中,對于 writeBytes() 寫入的數據,只能用 readBytes() 方法讀取。

    int QDataStream::writeRawData(const char *s, int len)

    將 s 中前 len 字節的數據寫入文件,返回值表示成功寫入的字節數。

    QDataStream 類也對<<和>>進行了重載,舉個簡單的例子,用 QDataStream 重新實現實例二:

    #include <QFile>
    #include <QDebug>
    #include <QDataStream>
    int main(int argc, char *argv[])
    {
        //指定要寫入文件的數據
        qint32 nums[5]={1,2,3,4,5};
        QFile file("D:/demo.dat");
        file.open(QIODevice::WriteOnly);
        //創建 QDataStream 對象
        QDataStream out(&file);
        //將 nums 數組中的整數逐個寫入到二進制文件中
        for(int i=0;i<5;i++){
          out << nums[i];
        }
        file.close();
        //再次打開文件,讀取文件中存儲的二進制數據
        file.open(QIODevice::ReadOnly);
        QDataStream in(&file);
        //讀取二進制文件中的數據
        while(!in.atEnd()){
            //每次讀取一個整數
            qint32 num;
            in >> num;
            qDebug() << num;
        }
        return 0;
    }
    

    輸出結果為:

    1
    2
    3
    4
    5

    Qt實現學生信息管理系統

    本節我們教大家用 Qt 實現一個帶界面的學生信息管理系統,完成后的系統主界面如下圖所示:

    圖 1 學生信息管理系統主界面

    該學生信息管理系統將學生信息保存到文件中,用戶借助界面上的表格、列表、按鈕、輸入框等控件,可以對學生信息進行查看、添加、刪除、查找、更改、保存等操作。

    學生信息管理系統的界面設計

    整個學生信息管理系統,需要設計兩個界面,一個是圖 1 所示的主界面,另一個是添加學生信息的界面,如下圖所示:

    圖 2 添加學生信息界面

    主界面的設計實現思路是:將 QHBoxLayout 作為主界面的布局工具,內部添加兩個 QGroupBox 分組框,從而將整個界面一分為二:

    左邊的分組框中添加一個 QTableWidget 表格控件,如果想讓表格控件的尺寸隨著主窗口尺寸的變化而變化,可以將 QTableWidget 框架添加到某個布局工具中(比如 QHBoxLayout、QVBoxLayout 等)。

    右邊的分組框中,向 QVBoxLayout 先后添加一個 QListWidget 和 QGridLayout,從而將右側分組框分為上下兩部分。在 QGridLayout 中放置添加、刪除、保存、退出按鈕以及一個 QLineEdit 單行輸入框。

    由此,主窗口就設計完成了。

    設計圖 2 所示的添加學生信息界面非常簡單,只需要自定義一個繼承自 QDialog 的窗口類,用 QVBoxLayout 作為該窗口的布局工具,并依次將 QFormLayout 和 QHBoxLayout 添加到 QVBoxLayout 中:

    向 QFormLayout 中添加多個單行輸入框;

    向 QHBoxLayout 中添加兩個按鈕。

    由此,添加學生信息的窗口就設計完成了。

    學生信息管理系統的功能實現

    整個學生信息管理系統,由以下幾個文件構成:

    圖 4 項目結構

    各個文件的作用分別是:

    StuInfoFile.pro:項目文件,整個項目的實現并沒有手動修改此文件中的內容;

    main.cpp:整個項目的主程序文件,用來啟動主界面;

    MainWidget.h 和 MainWidget.cpp:自定義的窗口類(繼承自 QWdiget),實現圖 1 所示的主界面,并完成主界面中所有控件的功能;

    EditStuMessBox.h 和 EditStuMessBox.cpp:自定義的窗口類(繼承自 QDialog),實現圖 2 所示的界面,并完成添加學生信息界面的功能;

    Tool.h 和 Tool.cpp:包含一些公共的宏定義和函數;

    image.qrc:為項目中的窗口添加 icon 圖標。

    整個項目的實現過程,需要重點說明的有以下幾點:

    1、合理使用信號和槽

    對于關聯在一起的信號函數和槽函數,有些場景中,需要調用 disconnect() 暫時取消它們之間的連接,后續再重新關聯它們。

    例如在本項目中,MainWidget.cpp 文件 flushTable() 函數的功能是更新 QTableWidget 表格控件中顯示的學生信息。更新學生信息之前,需要調用 disconnect() 函數切斷 cellChanged() 信號函數與其它所有槽函數的關聯,然后才能正常更新數據,更新完成后再恢復 cellChanged() 與其它槽函數的關聯。

    之所以更新數據前必須切斷 cellChanged() 與其它槽函數的關聯,是因為更新表格數據會不斷地觸發 cellChanged() 信號,最終會導致程序崩潰。

    2、從文件中刪除和更改某個學生信息

    實現對學生信息的“增刪查改”操作中,刪除和修改學生信息的實現過程更復雜一些,本項目中采取的實現方法是:不斷地從 student.txt 文件中讀取學生信息,判斷讀取到的學生信息是否需要刪除或修改,如果不需要,則直接寫入 student_temp.txt 文件;反之如果需要刪除,則直接將讀取到的信息丟棄,如果需要修改,則將修改后的學生信息寫入到 student_temp.txt 文件中。

    最終,student_temp.txt 文件中存儲的就是最新的學生信息,我們可以將 student.txt 文件中的內容刪除,然后將 student_temp.txt 文件中的內容拷貝到 student.txt 文件中,最后刪除 student_temp.txt 文件;也可以直接刪除 student.txt 文件,然后將 student_temp.txt 文件的名稱改為 student.txt,本項目中采用的是第二種方法。

    3、為項目添加圖標

    圖 4 中,image.qrc 文件是用來為項目添加圖標的,本項目選用的是 C 語言中文網的 icon 圖標,就存儲在當前項目的文件夾內,如下圖所示:

    圖 5 項目的所有文件

    首先,我們要在項目中新建一個后綴名為 qrc 的文件,鼠標移動到項目名上右擊選擇“添加新文件”,Qt Creator 會彈出如下對話框:

    圖 6 創建 qrc 文件

    選擇 “Qt -> Qt Rescource File”,可以創建一個 qrc 文件。在此基礎上,在 image.qrc 上右擊選擇“添加現有文件”,選中項目中的 logo.ico 圖標,就被成功地將圖標添加到項目中。

    接下來,哪個界面需要添加圖標,直接調用 setWindowIcon() 方法即可,例如:

    setWindowIcon(QIcon(":/logo.ico"));

    icon 圖標的存儲路徑可以通過右擊項目中的 logo.ico 圖標,選擇 "Copy Path “:logo.ico” 即可獲得。

    Qt打包程序詳解(適用于Windows平臺)

    分享 Qt 程序(項目)的方式無非兩種,要么直接分享程序的源代碼,要么分享程序生成的可執行文件。

    和直接分享源碼相比,大多數人會選擇后者。但遺憾地是,Qt Creator 默認以動態鏈接的方式生成可執行文件,該文件無法獨立運行,必須為其提供所需的動態鏈接庫。也就是說,只分享 Qt Creator 生成的可執行文件是不行的,必須將運行所需的動態鏈接庫一起分享,可執行文件才能在他人的電腦上正常運行。

    對 Qt 程序進行打包,指的就是找到可執行文件運行需要的所有動態庫文件,并將它們統一存放到指定的空文件夾里。本節以編寫完成的學生信息管理系統為例,給大家講解“怎樣在 Windows 平臺上打包一個 Qt 程序”。

    Qt程序打包

    打包 Qt 程序,通常選用以 release 模式生成的可執行文件。和 debug 模式相比,release 模式生成的可執行文件體積更小,運行效率更快。

    Qt Creator 默認以 debug 模式生成可執行文件,如下圖所示,可以手動修改 Qt Creator 以 release 模式生成可執行文件:

    圖 2 以 release 模式生成可執行文件

    選擇“Release”之后,再次運行程序,生成的可執行文件可以在下圖所示的路徑中找到:

    圖 3 可執行文件的存儲位置

    找到可執行文件之后,將其拷貝到一個空的文件夾,比如筆者將其拷貝到了新建的 D:\StuInfoFile 文件夾中,如下圖所示:

    圖 4 將可執行文件拷貝到新建的文件夾內

    此時的 StuInfoFile.exe 是無法運行的,雙擊它系統會提示類似“找不到 xxx.dll”的錯誤信息。

    在“開始”中找到 Qt 命令行程序并打開,如下圖所示:

    圖 5 Qt命令行程序

    在命令行中,先執行 “cd D:\StuInfoFile” 命令進入 StuInfoFile 文件夾,然后再執行 “windeployqt StuInfoFile.exe” 命令。windeployqt 是 Qt 提供的 Windows 平臺打包工具,它能找到 StuInfoFile.exe 可執行文件需要的所有動態鏈接庫,并將它們拷貝到當前文件夾中。

    成功執行命令之后,StuInfoFile 文件夾內會增加很多文件夾和文件(如下圖所示),這些都是 StuinfoFile.exe 執行所需要的。

    圖 6 打包后的 StuInfoFile 文件夾

    再次雙擊 StuInfoFile.exe,如果它可以成功執行,表明打包操作是成功的。我們可以直接將 StuInfoFile 文件夾分享給他人,只要是 Windows 平臺,都可以直接點擊運行 StuinfoFile.exe 文件。

    筆記本更換固態硬盤過程分享,SD10實際體驗

    升級固態硬盤 - 讓電腦煥發新生

    近期,隨著618大促活動的熱潮來臨,不少數碼玩家都把眼光瞄準在了固態硬盤的優惠促銷上。毫無疑問,固態硬盤無疑是目前電腦硬件升級的最佳選擇之一。無論是對于頻繁使用電腦的辦公人士、熱衷于游戲的發燒友,還是追求高速處理能力的創作者,升級固態硬盤無疑都能帶來質的飛躍。

    筆者便是在最近趁著618大促的機會,為自己的榮耀筆記本X16 Plus配備了一塊1TB容量的鎧俠SD10固態硬盤。在此過程中,我也對這款固態硬盤的安裝過程、性能表現等方面有了更深入的了解,因此特意與各位分享這次升級的親身體驗。

    鎧俠SD10 - 品質與性能兼具的存儲選擇

    對于大多數電腦用戶來說,在選購固態硬盤時通常會考慮三個關鍵因素:可靠性、速度和容量。而作為國際存儲大廠的鎧俠,其SD10系列產品無疑在這三方面都得到了出色的表現。

    首先是可靠性方面。作為東芝存儲器的后續品牌,鎧俠擁有多年的存儲器制造經驗,并且自家的AI半導體工廠更是全球最大之一,月產量占據全球30%以上。這樣的技術實力和生產規模,無疑能為用戶提供穩定可靠的產品。而在鎧俠SD10上,其還標稱了600TBW的寫入耐久性,并提供5年質保,這無疑大大增強了用戶的使用信心。

    其次是速度方面。鎧俠SD10采用了PCIe 4.0 x4接口,搭配NVMe 1.4協議,在CrystalDiskMark中實現了高達5054MB/s的順序讀速度和3969MB/s的順序寫速度,完全達到了官方公布的參數。再結合其能夠穩定維持的多隊列讀寫性能,可以說這款固態硬盤無疑能滿足當下主流電腦系統的高速存儲需求。

    最后是容量方面。 鎧俠SD10能夠提供高達2TB的容量選擇,足以應付日常各種數據存儲需求。而作為1TB版本的用戶,在實際使用中我發現其有效容量也達到了931.5GB,顯然鎧俠在提高使用壽命和性能方面做了一定的預留。

    簡單概括下來,作為一款面向普通消費級用戶的PCIe 4.0固態硬盤,鎧俠SD10無疑在品牌信賴度、性能表現和容量選擇上都得到了不俗的表現,堪稱是當前市面上性價比很高的存儲升級方案。

    榮耀筆記本X16 Plus換裝鎧俠SD10

    在擁有了鎧俠SD10這塊性能強悍的固態硬盤后,我便迫不及待地想把它安裝到自己的榮耀筆記本X16 Plus上。這臺輕薄本在去年5月份入手時,搭載的是AMD Ryzen 7 8845HS處理器和16GB內存,預裝了Windows 11系統,定位于AI全能輕薄本。不過出廠時只配備了512GB的SSD存儲空間,對于我這種喜歡存儲各種視頻剪輯素材、游戲資源的用戶來說,顯然有些捉襟見肘了。

    安裝過程十分簡單,只需要用T5H型號的螺絲刀依次卸下筆記本背面的10枚螺絲,再用撬片撬開背板即可。取下背板后,首先要記得斷開電池排線,然后就能看到筆記本內部的兩個M.2固態硬盤插槽位于主板右側。這兩個插槽分別支持M.2 2280和M.2 2242兩種規格,我選擇了右側的M.2 2280插口安裝鎧俠SD10。

    裝上新硬盤后,開機進入系統,在磁盤管理中對鎧俠SD10進行了簡單的格式化操作。這個過程中我注意到,鎧俠SD10的有效容量為931.5GB,顯然預留了一部分空間用于優化性能和增強耐久性。

    值得一提的是,鎧俠還為自家的固態硬盤專門設計了"SSD Utility"這款磁盤管理軟件。通過它,用戶可以更直觀地查看磁盤的容量、剩余壽命、健康狀態、溫度等信息,并能進行固件更新、安全擦除、先進格式化等操作。這無疑為用戶提供了一個便捷管理工具。

    升級鎧俠SD10后,榮耀筆記本X16 Plus的整體使用體驗得到了大幅提升。從日常文檔編輯、網頁瀏覽到視頻剪輯、游戲運行,整體響應速度都有了明顯改善。比如在將一個23GB的藍光電影復制到鎧俠SD10上時,平均速度就能穩定在1.2GB/s以上;再把一個53.8GB的文件夾拷貝過去,初始速度可以達到935MB/s,隨后還能攀升到1GB/s左右。這樣的傳輸效率相比原有的SSD可謂是質的飛躍。

    綜合使用下來,我對鎧俠SD10這款固態硬盤的表現非常滿意。它不僅在品牌信賴度、性能參數上做到了出眾,在實際應用中也展現出了卓越的實際性能。對于追求速度與可靠性的用戶來說,鎧俠SD10無疑是一個很不錯的升級選擇。

    AI全能輕薄本再出發

    有了鎧俠SD10這塊高性能固態硬盤的加持,我的榮耀筆記本X16 Plus煥然一新,無論是日常辦公、視頻編輯還是游戲娛樂,都能帶來質的飛躍。如今它不僅擁有強勁的AMD Ryzen處理器和16GB內存,還搭載了可靠耐用、極速響應的鎧俠固態硬盤,堪稱是一臺真正的AI全能輕薄本。

    對于許多喜歡DIY電腦硬件或追求極致性能的用戶來說,固態硬盤的升級無疑是非常值得一做的事情。在當下的市場環境下,鎧俠SD10無疑是一個性價比很高的選擇。它不僅在品牌信賴度、技術實力上有充分保證,在實際使用體驗中也能帶來質的飛躍。

    所謂"一臺電腦能走多遠,關鍵在于換上什么樣的硬件"。對我而言,借助鎧俠SD10的升級,原本稍顯不足的榮耀筆記本X16 Plus得到了很大的提升,再次煥發出了青春活力。相信對于許多數碼玩家而言,也都在期待通過固態硬盤的升級,讓自己的電腦裝備實現質的飛躍。

    固態硬盤的未來發展 - 引領信息高速時代

    隨著鎧俠SD10的順利安裝,我的榮耀筆記本X16 Plus煥發出了新的活力。不僅響應速度大幅提升,存儲容量也得到了大幅擴充。這次升級不僅讓我的日常辦公體驗煥然一新,也為視頻剪輯、游戲運行等專業應用帶來了質的飛躍。

    可以說,在當下這個信息高速發展的時代,擁有高性能存儲設備已經成為每一臺電腦所需具備的基本條件。隨著大數據、人工智能等前沿技術的興起,以及 4K、8K視頻內容的不斷普及,對存儲設備的要求也越來越高。無論是對于辦公自動化、創意設計,還是沉浸式游戲體驗,都離不開高速、大容量、可靠的存儲系統支撐。

    而固態硬盤憑借其出色的讀寫性能、低功耗和更高的可靠性,已經成為現代電腦硬件中的標配。相比傳統機械硬盤,固態硬盤毫無疑問能為用戶帶來質的飛躍。不過在當前的固態硬盤市場上,品牌和產品之間的差異性也是顯而易見的。擁有雄厚技術實力和資金實力的大廠,往往能提供更加穩定可靠的產品,這也是我當初選擇鎧俠SD10的重要考量因素之一。

    展望未來,隨著半導體制造工藝的不斷進步,固態硬盤必將迎來新一輪的性能革新。PCIe 5.0接口、3D XPoint非易失性內存等前沿技術的應用,將進一步提升固態硬盤的傳輸帶寬和訪問延遲。同時,隨著固態硬盤容量的不斷擴大,以及成本的持續下降,它必將在更廣泛的應用場景中替代傳統機械硬盤。

    可以預見,在不遠的將來,無論是普通用戶,還是專業創作者,都將能享受到固態硬盤帶來的極速體驗。從日常文檔處理、網頁瀏覽,到視頻剪輯、游戲運行,整個系統的響應速度和操作流暢度都將煥然一新。這不僅能大幅提升用戶的生產力和創作效率,也必將推動信息高速時代的到來。

    對于當下正在考慮電腦硬件升級的朋友們來說,固態硬盤無疑是最值得關注的"升級重點"。無論是追求極致性能的發燒友,還是注重日常使用體驗的普通用戶,都應該認真考慮將固態硬盤列入升級清單。作為優秀的存儲品牌,鎧俠無疑是當前市場上很不錯的選擇。它不僅在產品可靠性和性能表現上有出色表現,在未來的發展前景上也值得期待。

    讓我們一起期待,通過固態硬盤的不斷進化,掀起新一輪信息高速時代的浪潮。無論是辦公自動化、內容創作,還是沉浸式游戲體驗,都將因此煥發出更強的生命力。相信不久的將來,擁有高性能固態硬盤的電腦設備,必將成為每個人日常生活、工作和娛樂中不可或缺的重要伙伴。

    免責聲明:文章描述過程、圖片都來源于網絡,此文章旨在倡導社會正能量,無低俗等不良引導。如涉及版權或者人物侵權問題,請及時聯系我們,我們將第一時間刪除內容!如有事件存疑部分,聯系后即刻刪除或作出更改。

網站首頁   |    關于我們   |    公司新聞   |    產品方案   |    用戶案例   |    售后服務   |    合作伙伴   |    人才招聘   |   

友情鏈接: 餐飲加盟

地址:北京市海淀區    電話:010-     郵箱:@126.com

備案號:冀ICP備2024067069號-3 北京科技有限公司版權所有