Qt 5入門(mén)指南之Qt Quick編程示例
編程示例
本文引用地址:http://dyxdggzs.com/article/201808/385048.htm使用Qt創(chuàng )建應用程序是十分簡(jiǎn)單的??紤]到你的使用習慣,我們編寫(xiě)了兩套教程來(lái)實(shí)現兩個(gè)相似的應用程序,但是使用了
不同的方法。在開(kāi)始之前,請確保你已經(jīng)下載了QtSDK的商業(yè)版本或者開(kāi)源版本,并且你也已經(jīng)熟悉了Qt的開(kāi)發(fā)工具。QtSDK
提供了QtCreator集成開(kāi)發(fā)環(huán)境使得開(kāi)發(fā)Qt的應用程序十分簡(jiǎn)單。
用戶(hù)界面的選擇
除了直觀(guān)上知道Qt是跨平臺的,提供了包括線(xiàn)程,網(wǎng)絡(luò )通信以及視頻回放和網(wǎng)絡(luò )攝像頭等的跨平臺抽象外,Qt提供了兩種
獨立的方法創(chuàng )建用戶(hù)界面。
QtQuick模塊為創(chuàng )建流暢的、活生生的用戶(hù)界面提供了一種標記語(yǔ)言。這種方式適合那些需要動(dòng)畫(huà)元素的界面,以及應用程序
主要運行在小屏幕和多點(diǎn)觸控的設備上的場(chǎng)景。
QtWidgets模塊針對傳統桌面提供了更多的支持,和目標平臺做了更多的集成,無(wú)論目標平臺是MacOSX,Windows,KDE還會(huì )Gnome。它是一個(gè)非常高效的基于C++的類(lèi)庫,包含了很多常見(jiàn)的用戶(hù)界面組件,你可以非常容易的為這些已存在的組件
擴展新的功能。
你選擇那個(gè)模塊來(lái)創(chuàng )建用戶(hù)界面取決于你想創(chuàng )建怎樣的應用程序。其它的方法在余下的Qt庫中都是一樣的,所以你可以盡
可能的將應用程序中邏輯處理的代碼寫(xiě)得更加獨立一些。當你熟悉了下面兩個(gè)示例,你可以再做決定選擇哪一個(gè)模塊來(lái)創(chuàng )建用
戶(hù)界面。對于更加詳細的信息,可以查看用戶(hù)界面信息。
教程
這里有兩個(gè)用于創(chuàng )建兩個(gè)相似應用程序的例子。一個(gè)是使用QtQuick創(chuàng )建用戶(hù)界面,而另一個(gè)則是使用QtWidgets來(lái)創(chuàng )建用戶(hù)界面。
使用QtQuick開(kāi)始編程
歡迎來(lái)到QML的世界。在這個(gè)示例中我們將會(huì )使用QML創(chuàng )建一個(gè)簡(jiǎn)單的文本編輯器應用程序。在閱讀完這個(gè)指南之后,
你應該可以使用QML和QtC++開(kāi)發(fā)自己的應用程序。
QML構建用戶(hù)界面
本應用程序是一個(gè)簡(jiǎn)單的文本編輯器,可以加載、保存和執行一些文本的操作。這個(gè)指南將會(huì )包含兩個(gè)部分。第一部分將會(huì )
涉及到應用程序的布局以及使用QML語(yǔ)言。在第二部分,我們將會(huì )使用QtC++實(shí)現文本的加載和保存。使用Qt的元對象系統我們
可以將C++的功能作為QML元素的屬性使用。使用QML和QtC++,我們可以將界面邏輯和應用程序邏輯分離開(kāi)。

最終的源代碼在examples/tutorials/gettingStartedQml目錄。你也許需要先編譯examples/tutprials/gettingStartedQml/filedialog目錄下的
C++插件。這一步會(huì )將C++插件放在QML能夠找到的目錄下。要啟動(dòng)這個(gè)應用程序,僅僅需要使用qmlscene工具,將QML作為
參數傳遞給這個(gè)工具。C++的部分假設了閱讀者已經(jīng)掌握了基本的Qt編譯過(guò)程。
教程章節:
定義按鈕和菜單
實(shí)現菜單欄
編譯文本編輯器
裝飾文本編輯器
使用QtC++擴展QML
定義一個(gè)按鈕和菜單
基本組件——按鈕
我們以構建一個(gè)按鈕開(kāi)始我們的文本編輯器。在功能上,按鈕有一個(gè)鼠標敏感區域和一個(gè)標簽。當用戶(hù)點(diǎn)擊按鈕的時(shí)候,
按鈕執行一個(gè)動(dòng)作。
在QML中,最基本的可視化單元就是矩形(Rectangle)元素。矩形元素具有控制元素外觀(guān)和位置的屬性。
首先,導入QtQuick2.0允許qmlscene工具加載QML元素以便稍后使用。這一行代碼在所有的QML文件中都存在。需要注意
的是,我們導入Qt的模塊的時(shí)候也導入了版本號。
這個(gè)簡(jiǎn)單的矩形有一個(gè)唯一的標簽”simplebutton”,這就是id屬性。矩形元素的屬性是通過(guò)依次羅列屬性,中間以分號間隔,
然后就是屬性的值。在示例代碼中,”grey”顏色就綁定到了矩形的顏色屬性。類(lèi)似地,我們也綁定了該矩形的高度和寬度。
Text元素是一個(gè)不可編輯的文本區域。我們給這個(gè)文本框命名為”buttonlabel”。我們通過(guò)將值綁定到”text”屬性來(lái)設置該文本
框的文字。這個(gè)文本框在矩形的中間,我們將文本框的”anchors”設置為其父親,也就是前面提到的simplebutton。Anchors也可以
綁定到其它元素的anchors,使得布局更加的簡(jiǎn)單。
我們將這些代碼保存為SimpleButton.qml。使用這個(gè)文件的文件名作為參數調用qmlscene工具,將會(huì )出現如下的效果:

要實(shí)現按鈕的功能,我們可以使用QML的事件處理機制。QML的事件處理機制和Qt的信號-槽機制十分類(lèi)似。信號被發(fā)射
然后關(guān)聯(lián)的槽函數被調用。

在我們的simplebutton矩形中,我們包含了一個(gè)MouseArea元素。MouseArea元素描述了可交互的區域,也就是鼠標的移動(dòng)會(huì )
被檢測的區域。在這個(gè)例子中,我們將MouseArea的anchor設置為它的父親,也就是前面提到的simplebutton。Anchors.fill是獲取
指定屬性的一種語(yǔ)法表達方式。fill是屬性簇anchors中的一個(gè)特定屬性。QML使用了基于anchor的布局,元素可以anchor其它的元
素,創(chuàng )建健壯的布局。
當鼠標在MouseArea區域中移動(dòng)時(shí)MouseArea有許多事件處理者。其中的一個(gè)事件處理者就是onClicked,該事件處理會(huì )在允
許鼠標點(diǎn)擊的區域中點(diǎn)擊鼠標時(shí)候被調用,默認是左鍵單擊。我們可以將一個(gè)動(dòng)作綁定到onClicked處理句柄。在我們的示例中
,當鼠標點(diǎn)擊時(shí),console.log()輸出文本。Console.log()函數是一個(gè)有用的調試輸出函數。
如下的代碼足夠完成顯示按鈕且在鼠標單擊的時(shí)候輸出文本。

一個(gè)功能齊全的按鈕在Button.qml中。示例代碼中有部分被省略了,因為這些代碼要么在之前介紹過(guò)了,要么就是與本章
介紹的內容不是很相關(guān)。
我們可以使用屬性類(lèi)型名稱(chēng)的語(yǔ)法來(lái)自定義屬性。在示例代碼中,buttonColor屬性就是自定義的并且被賦值為”lightblue”。buttonColor在后面就被使用到了,用來(lái)根據不同操作填充不同的顏色。值得注意的是,屬性的賦值使用的是”=”,
而屬性的值綁定使用的則是”:”。自定義的屬性使得內部元素的可見(jiàn)范圍可以超出矩形的范圍。QML基本類(lèi)型有int,string,real和variant。通過(guò)綁定onEntered和onExited信號處理到顏色上,當鼠標停留在按鈕之上,按鈕的邊框將會(huì )變?yōu)辄S
顏色,并且在鼠標離開(kāi)按鈕的時(shí)候恢復為原來(lái)的顏色。
我們通過(guò)將signal關(guān)鍵字放在信號名稱(chēng)之前,自定義了一個(gè)buttonClick()信號在Button.qml中,所有的信號的處理者都是自動(dòng)
被創(chuàng )建的,這是通過(guò)簡(jiǎn)單在信號的名字前面加上”on”這個(gè)單詞。顯然,onButtonClick就是buttonClick的處理者。onButtonClick會(huì )
被賦予一些動(dòng)作。在我們的按鈕示例中,onClicked鼠標處理者將會(huì )簡(jiǎn)單的調用onButtonClick,功能就是現實(shí)一個(gè)文本。
onButtonClick使得外部對象可以十分輕易的獲取按鈕的鼠標區域。例如:將設有許多的元素,這些元素擁有許多的MouseArea,
那么一個(gè)buttonClick信號可以在許多的MouseArea做出區分,使得分別處理幾個(gè)MouseArea更加簡(jiǎn)單。
我們現在已經(jīng)具備了基本的知識:在QML中實(shí)現基本元素并可以處理鼠標移動(dòng)事件。我們在一個(gè)巨型中創(chuàng )建一個(gè)文本框,自定義了屬性,針對鼠標移動(dòng)實(shí)現了相應的處理。在元素中創(chuàng )建元素的思想貫穿著(zhù)整個(gè)示例。
現在該按鈕還沒(méi)有什么用,除非他作為組件可以執行一些動(dòng)作。在下面一節,我們將會(huì )快速的創(chuàng )建一個(gè)菜單,包含幾個(gè)這樣的按鈕。

創(chuàng )建一個(gè)菜單頁(yè)
在這一階段,我們將會(huì )介紹如何在一個(gè)單獨的QML文件中創(chuàng )建元素并指定動(dòng)作。在這一節,我們將會(huì )介紹如何導入QML元素
以及如何使用已經(jīng)存在的組件構建新的組件。
菜單顯示了一個(gè)列表內容,每一個(gè)元素都用執行一個(gè)特殊動(dòng)作的功能。在QML中,我們可以使用幾種方式創(chuàng )建菜單。首先我們會(huì )創(chuàng )建一個(gè)包含按鈕的菜單,每一個(gè)按鈕執行不同的動(dòng)作。菜單的代碼在文件FileMenu.qml中。

上面的語(yǔ)法展示了如何導入關(guān)鍵字。這里需要使用JavaScript文件,或者使用不在同一目錄下的QML文件。因為Button.qml文件和FileMenu.qml文件在同一個(gè)目錄下,因此我們無(wú)需導入Button.qml文件就可以使用它。我們可以直接通過(guò)聲明Button()創(chuàng )建按鈕,
類(lèi)似Rectangle的聲明。

在FileMenu.qml文件中聲明了三個(gè)Button元素。它們都聲明在一個(gè)Row元素內。該元素將其子元素水平放置。Button是在Button.qml文件中聲明的,這種用法和上一節的用法一致。在新創(chuàng )建的button中,我們可以將其屬性綁定為新值,覆蓋它們在Button.qml中綁定的默認值。exitButton按鈕在被按下的時(shí)候整個(gè)應用程序就會(huì )退出。值得注意的是:在Button.qml中定義的信號onButtonClick將會(huì )在FileMenu.qml中被調用,除了exitButton的onButtonClick事件處理者。

Row是在一個(gè)Rectangle中聲明的,創(chuàng )建了一個(gè)用于防止按鈕的矩形容器。這個(gè)矩形創(chuàng )建了一個(gè)間接的方式用于組織在一個(gè)菜單中
的按鈕行。編輯菜單的聲明和之前菜單聲明十分類(lèi)似。菜單中的按鈕的標簽為:Copy,Paste和SelectAll。

實(shí)現一個(gè)菜單欄
我們的文本編輯程序需要使用菜單欄來(lái)顯示菜單。菜單欄將會(huì )切換到不同的菜單,并且用戶(hù)可以選擇那些菜單可以顯示。
菜單的切換意味著(zhù)菜單需要更多的結構而不僅僅是將它們成行的顯示出來(lái)。QML使用模型和視圖來(lái)組織數據以及顯示結構化的
數據。
使用數據模型和視圖
QML有不同的數據視圖來(lái)顯示數據模型。我們的菜單欄會(huì )將菜單以列表的方式顯示出來(lái),也包含一個(gè)用于顯示菜單名的頭部。菜單列表是在VisualItemModel中聲明的。VisualItemModel元素包含那些已經(jīng)具有視圖的元素,例如矩形以及導入的UI元素。其它的
模型類(lèi)型,例如ListModel元素需要一個(gè)代理來(lái)顯示它的數據。
我們在menuListModel中聲明兩個(gè)可視化元素:FileMenu和EditMenu。我定制了這兩個(gè)菜單并且使用ListView來(lái)顯示它們。MenuBar.qml文件包含了QML聲明,一個(gè)簡(jiǎn)單的編輯菜單定義在EditMenu.qml文件中:
ListView元素將會(huì )依照代理來(lái)顯示模型。代理可能聲明模型元素以Row元素顯示,也可能以網(wǎng)格的方式顯示。我們的menuListModel已經(jīng)包含了可視化元素,因此,我們不需要聲明代理。

另外,ListView繼承自Flickable,使得列表可以響應鼠標的拖拽以及其它的一些手勢。上面代碼的最后部分設置了Flickable
屬性用于創(chuàng )建我們想要的滑動(dòng)操作。特別是highlightMoveDuration屬性改變滑動(dòng)轉換的周期。一個(gè)highlightMoveDuration使得菜單
間的切換更加緩慢。
ListView通過(guò)一個(gè)索引(index)來(lái)維護模型元素,并且模型中的每一個(gè)可視化元素都可以通過(guò)索引來(lái)獲取,索引的順序是根據
元素被聲明的順序定義的。改變currentIndex的值將會(huì )導ListView中高亮的元素改變。我們菜單欄的頭部證明了這種效果。這里有
兩個(gè)按鈕,點(diǎn)擊任何一個(gè)都會(huì )切換當前的菜單。當點(diǎn)擊fileButton的時(shí)候,菜單切換到FileMenu,并且索引變?yōu)?,因為FileMenu在menuListModel中是最先聲明的,editButton類(lèi)似。labelList矩形有一個(gè)取值為1的z變量,這意味著(zhù)它是在菜單欄的上
面顯示(空間坐標系)。z值較大的元素始終在z值較小的元素的上面顯示。默認的z值是0。

目前創(chuàng )建的菜單欄僅僅具有菜單切換的效果,通過(guò)點(diǎn)擊頭部的兩個(gè)按鈕來(lái)進(jìn)行切換:

構建文本編輯器
聲明一個(gè)文本區域(TextArea)
如果我們的文本編輯器不具有一個(gè)可編輯的區域,那么他就不能被稱(chēng)為文本編輯器。QML的TextEdit元素允許聲明一個(gè)
多行編輯的文本區域。TextEdit元素和Text元素是有區別的,后者不允許用戶(hù)對文本進(jìn)行編輯。

上面設置了編輯器的前景色屬性和環(huán)繞文字的模式。TextEdit區域是包含在一個(gè)flickable的區域中的,這確保了當文字光標
了當前的顯示區域,那么文本內容會(huì )自動(dòng)滾動(dòng)。函數ensureVisible()將會(huì )檢查鼠標是否處在可見(jiàn)區域的外面并且根據檢查的結果
移動(dòng)滾動(dòng)文本區域。QML使用JavaScript語(yǔ)法作為其腳本,正如前面提到的,JavaScript可以導入并且在QML中使用。

為文本編輯器組裝組件
我們現在已經(jīng)準備好了使用QML為我們的文本編輯器創(chuàng )建布局。文本編輯器包含兩個(gè)組件,已經(jīng)創(chuàng )建的菜單欄和文本區域。QML允許我們重用這些組件,因此我們可以通過(guò)導入組件以及在必要的時(shí)候做一些定制來(lái)簡(jiǎn)化我們的代碼。我們的文本
編輯器將窗口分為兩個(gè)部分:屏幕的1/3用來(lái)顯示菜單欄,另外的2/3用來(lái)顯示文本區域。菜單欄在其他的元素上面顯示(空間坐標系)。

通過(guò)導入可重用的組件,我們的文本編輯器的代碼看起來(lái)更加簡(jiǎn)單了。我們可以定制自己的主應用程序而不必擔心那些已經(jīng)
指定動(dòng)作的屬性。使用這種方法,應用程序的布局和UI組件可以更加簡(jiǎn)單的被創(chuàng )建。

裝飾文本編輯器
實(shí)現一個(gè)繪圖的接口
我們的文本編輯器看起來(lái)十分的簡(jiǎn)單,因此我們需要裝飾一下。使用QML,我們可以為我們的文本編輯器定義轉換和動(dòng)畫(huà)。
我們的菜單欄占據1/3的屏幕,因此只在我們需要的時(shí)候才顯示它這個(gè)功能將會(huì )十分有用。
我添加了一個(gè)繪畫(huà)的接口,在我們單擊的時(shí)候,該接口將會(huì )收起或者展開(kāi)菜單欄。在我們的實(shí)現中,我們使用了一個(gè)十分小
的矩形用于鼠標點(diǎn)擊。繪畫(huà)接口和應用程序都有兩種狀態(tài):繪畫(huà)接口是打開(kāi)的和繪畫(huà)接口是關(guān)閉的。繪畫(huà)(drawer)元素是一個(gè)矩形,但是它的高度很小。這里有一個(gè)內嵌在繪畫(huà)元素中間的Image元素,用于展示一個(gè)箭頭圖標。繪畫(huà)元素將會(huì )通過(guò)screen標簽賦予整個(gè)
應用程序一個(gè)狀態(tài),無(wú)論用戶(hù)在什么時(shí)候點(diǎn)擊鼠標區域

一個(gè)狀態(tài)僅僅是定義在State元素內部的一系列配置的集合。我們可以列舉一系列的狀態(tài)通過(guò)綁定到states屬性。在我們的
應用程序中,兩種狀態(tài)分別被稱(chēng)為DRAWER_CLOSED和DRAWER_OPEN。元素的配置都是在PropertyChanges中聲明的。在DRAWER_OPEN狀態(tài)中,有四個(gè)元素將會(huì )被改變屬性。第一個(gè)目標,menubar將會(huì )改變自己的y屬性為0。類(lèi)似的textArea在DRAWER_OPEN狀態(tài)中將會(huì )降低到一個(gè)新的位置。

狀態(tài)的轉變是突兀的并且是需要做平滑轉換的。在狀態(tài)之間的轉換是通過(guò)Transition元素定義的,定義好了之后可以綁定到
元素的transitions屬性。我們的文本編輯器有一個(gè)狀態(tài)轉換器。我們的文本編輯器需要在DRAWER_OPEN和DRAWER_CLOSE
兩種狀態(tài)之間轉換。重要的是,轉換器需要一個(gè)from狀態(tài)和一個(gè)to狀態(tài),我們可以使用*號通配符將該轉換器應用于所有的狀態(tài)
轉換。
在狀態(tài)的轉換過(guò)程中,我們可以為屬性的變化指定動(dòng)畫(huà)。我們的menuBar位置在y:0到y:-partition之前轉換,我們可以使用NumberAnimation元素使得這個(gè)轉換過(guò)程更生動(dòng)。我們聲明了目標屬性將會(huì )動(dòng)畫(huà)一定時(shí)間,并且使用特定的曲線(xiàn)。一個(gè)曲線(xiàn)
控制著(zhù)動(dòng)畫(huà)的轉換以及狀態(tài)轉換間的動(dòng)作。我們選擇的特定曲線(xiàn)是Easing.OutQuint,該曲線(xiàn)在接近終點(diǎn)的時(shí)候運動(dòng)速度變慢。
可以看看有關(guān)QML動(dòng)畫(huà)的內容。

另一種方式實(shí)現屬性變化時(shí)候的動(dòng)畫(huà)效果就是聲明一個(gè)Behavior元素。一個(gè)轉換器僅僅在狀態(tài)改變的時(shí)候工作,然而B(niǎo)ehavior
可以在一般屬性發(fā)生改變的時(shí)候工作。在文本編輯器中,當箭頭的旋轉屬性改變時(shí),箭頭有一個(gè)NumberAnimation的動(dòng)畫(huà)。

回到我們對于組件的狀態(tài)和動(dòng)畫(huà)知識,我們可以提高我們組件的表現力。在Button.qml中,在按鈕被單擊的時(shí)候,我們可以
添加顏色(color)和比例(scale)屬性改變。顏色的動(dòng)畫(huà)使用的是ColorAnimation元素數量的動(dòng)畫(huà)使用的是NumberAnimation。下面使
用的”onpropertyName”的語(yǔ)法形式對于目標是單個(gè)屬性而言是十分有幫助的。

另外,我們可以通過(guò)使用顏色效果,例如:光柵效果等來(lái)增強QML組件的表現力。聲明一個(gè)Gradient元素將會(huì )覆蓋該元素的color屬性。你可以在gradient中使用GradiendStop元素聲明一種顏色。梯度(gradient)屬性使用的是比例值,介于0.0和1.0之間。

這個(gè)梯度值是被菜單欄使用的。最初的顏色是0.0,最后的則是1.0.
接下來(lái)怎么做
我們已經(jīng)完成了一個(gè)簡(jiǎn)易的文本編輯器的界面。接下來(lái)我們的UI界面已經(jīng)完成,那么我們就可以使用Qt和C++來(lái)完成程序的邏輯部分。QML最為一個(gè)不錯的原型工具,將應用程序的邏輯部分和UI設計隔離開(kāi)。

使用Qt Cpp擴展QML
現在,我們已經(jīng)有了文本編輯框的布局,我們現在就使用C++實(shí)現文本編輯框的功能部分。使用QML和C++允許我們使用Qt創(chuàng )建
應用程序的邏輯部分。我們可以使用Qt的Quick類(lèi)在C++應用程序中創(chuàng )建QML上下文,并且使用QQuickView顯示QML元素??蛇x的,我們也可以將C++代碼導出為一個(gè)qmlscene工具可以讀取的插件。在本示例中,我們將會(huì )使用C++實(shí)現加載和保存文本的功能,并且將C++代碼導出為一個(gè)插件。在這種方式下,我們僅僅需要直接加載QML文件,而不是運行可執行程序。
導出C++類(lèi)到QML
我們使用Qt和C++實(shí)現加載和保存文本的功能,通過(guò)注冊C++的類(lèi)和方法都可以在QML中被調用。C++類(lèi)需要被編譯為Qt插
件,并且QML文件需要知道這個(gè)插件所處目錄。
對于我們的文本編輯器程序來(lái)說(shuō),我們需要創(chuàng )建如下的內容:
Directory類(lèi),該類(lèi)用于處理與目錄相關(guān)的操作;
File類(lèi),該類(lèi)繼承自QObject,列出一個(gè)目錄下的所有文件;
插件類(lèi),該類(lèi)將會(huì )注冊到QML上下文中;
Qt工程文件,使得這個(gè)Qt工程被編譯成插件;
一個(gè)qmldir文件,用于告訴qmlscene工具插件類(lèi)所處的目錄。
編譯Qt插件
要編譯一個(gè)插件,我們需要將下面的內容放置到Qt工程文件中。首先是必須添加到Qt工程文件中的源文件,頭文件以及Qt模塊。所有的C++代碼和工程文件都在filedialog目錄下:

特別需要注意的是,我們將qml模塊也連接到該工程中,并且配置為插件模式,使用lib模板。我們將編譯生成的插件放置在
上一層的plugins目錄下。
注冊一個(gè)類(lèi)到QML中

我們需要使用Q_PLUGIN_METADATA宏來(lái)導出插件。注意,在我們的dialogPlugin.h文件中,我們將Q_OBJECT宏放置在我們
類(lèi)的最上面。因為我們需要對工程文件運行qmake來(lái)產(chǎn)生必要的元對象代碼。
我們的插件類(lèi):DialogPlugin是QQmlExtensionPlugin的一個(gè)子類(lèi)。我們需要實(shí)現繼承的方法:registerTypes()。dialogPlugin.cpp文
件內容如下:

registerTypes()方法將我們的File和Directory類(lèi)注冊到QML中。該方法需要類(lèi)的名稱(chēng)作為它的模板,一個(gè)主版本號,一個(gè)次版本
號以及類(lèi)名。
在C++類(lèi)中創(chuàng )建QML屬性
我們可以使用C++和Qt的元對象系統來(lái)創(chuàng )建QML元素和屬性。我們可以使用信號-槽機制實(shí)現屬性,使得Qt可以識別這些屬性。然后,這些屬性就可以在QML中使用了。
針對我們的文本編輯器應用,我們需要加載和保存文本。典型地,這些特性需要包含一個(gè)文件對話(huà)框。幸運地是我們可以使用QDir、QFile和QTextStream來(lái)實(shí)現目錄的讀取以及輸入輸出流。

Directory類(lèi)使用了Qt的元對象系統來(lái)注冊一些屬性以便完成文件處理。Directory類(lèi)將會(huì )被作為一個(gè)插件導出,并且在QML中作為Directory元素使用。每一個(gè)使用Q_PROPERTY宏定義的屬性都是一個(gè)QML屬性。
Q_PROPERTY定義一個(gè)讀和寫(xiě)的屬性就好比是元對象系統中讀和寫(xiě)函數一樣。例如:filename屬性,是QString類(lèi)型,可使用filename()方法讀取,使用setFilename()設置。另外,這里有一個(gè)信號關(guān)聯(lián)到了filename屬性:filenameChanged(),當filename屬性
改變的時(shí)候就會(huì )發(fā)射這個(gè)信號。讀和寫(xiě)函數在頭文件中是以public關(guān)鍵字聲明的。
類(lèi)似的,我們也聲明了其它一些將會(huì )使用到的屬性。filesCount屬性表面一個(gè)目錄下的文件數。Filename屬性被設置為當前選
中的文件的文件名,并且加載/保存文件的內容都存放在屬性fileContent中。

Files列表屬性是在該目錄下過(guò)濾后剩下的文件列表。Directory類(lèi)實(shí)現了過(guò)濾掉非法的文本文件,僅僅以”.txt”結尾的文件才是
合法的。Qlists可以通過(guò)在C++中聲明為QQmlListProperty屬性在QML文件中使用。模板對象都需要繼承自QObject,因此File類(lèi)也
需要從QObject集成。在Directory類(lèi)中,File對象列表保存在一個(gè)名為m_fileList的QList中。

這些屬性可以在QML中作為Directory元素的屬性使用。需要注意的是,我們不需要再C++代碼中創(chuàng )建一個(gè)表示標簽的”id”屬性。

因為QML使用了JavaScript的語(yǔ)法和結構,因此我們可以在文件列表中迭代并獲取其屬性。要獲取第一個(gè)文件的名字屬性,
我們可以使用”files[0].name”。
普通的C++函數也可以在QML中使用。文件加載和保存函數使用C++代碼實(shí)現,并且使用Q_INVOKABLE宏聲明??蛇x的
是,我們可以將這些函數作為槽函數聲明,然后這些函數也可以在QML中使用。

Directory類(lèi)童謠需要在目錄內容發(fā)生改變的時(shí)候通知其它的對象。這個(gè)特性可以使用信號實(shí)現。在前面已經(jīng)提到過(guò),QML
信號有一個(gè)以on開(kāi)頭的信號處理器。這里我們將信號命名為directoryChanged,在目錄被刷新的時(shí)候該信號被發(fā)射。目錄刷新僅
僅是再次加載目錄內容,并且更新合法的文件列表。QML元素可以通過(guò)連接到onDirectoryChanged信號處理上得到目錄被改變
的通知。
List屬性需要繼續被討論。這是因為list屬性使用回調函數訪(fǎng)問(wèn)和修改list的內容。List屬性的類(lèi)型是QQmlListProperty
論在什么時(shí)候訪(fǎng)問(wèn)列表,訪(fǎng)問(wèn)器(accessorfunction)都應該返回一個(gè)QQmlListProperty
此要構造QQmlListProperty屬性,我們需要將列表的訪(fǎng)問(wèn)器和修改器的函數指針作為參數傳遞給構造器。同樣我們需要一個(gè)指向
File列表的QList指針。

構造器將指針傳遞給追加列表的函數,計算列表大小的函數,使用索引(index)獲取條目的函數以及清空列表的函數。至于追加
列表的函數是必須的。需要注意的是:函數指針必須和AppendFunction、CountFunction、AtFunction以及ClearFunction相匹配。

為了簡(jiǎn)化文件對話(huà)框,Directory類(lèi)實(shí)現了過(guò)濾掉非法的文本文件(不以”.txt”結尾的文件)。如果一個(gè)文件不是以”.txt”結尾,那么
在它在文件對話(huà)框中就是不可見(jiàn)的。同樣,我們的實(shí)現也確保了文件的保存是以”.txt”結尾的。Directory類(lèi)使用QTextStream類(lèi)讀取
文件并將數據寫(xiě)到文件中的。
使用我們的Directory元素,我們可以將文件組織為列表,我們可以知道目錄下有多少文件,可以獲取文件的名稱(chēng)和內容,并且
在目錄內容改變的時(shí)候得到通知。
要編譯這個(gè)插件,我們需要在filedialog.pro文件上運行qmake命令,然后運行make命令來(lái)編譯并將插件拷貝到plugins目錄。
在QML中導入插件
Qmlscene工具將與應用程序同一目錄下的文件直接導入。我們也可以通過(guò)創(chuàng )建一個(gè)qmldir文件,包含我們需要導入的QML文件
的位置。Qmldir文件也可以存儲插件以及其它資源的位置。

我們剛剛創(chuàng )建的插件是FileDialog,這是在工程文件的TARGET域指定的。編譯后的插件存放在plugins目錄下。
將FileDialog集成到FileMenu
我們的FileMenu需要顯示一個(gè)FileDialog元素,FileDialog元素包含了一個(gè)目錄下文件的列表,允許用戶(hù)通過(guò)在列表中點(diǎn)擊來(lái)選
擇文件。我們同樣需要指定save,load,new三個(gè)按鈕來(lái)獲取這些動(dòng)作。FileMenu包含了一個(gè)可編輯的文本輸入框,允許用戶(hù)通過(guò)鍵盤(pán)
輸入文件名。
Directory元素在FileMenu.qml文件中被使用到,并且它通知FileDialog元素目錄的內容得到了更新。這個(gè)通知是在信號處理者onDirectoryChanged中處理的。

為了繼續保持我們的應用程序簡(jiǎn)單,文件對話(huà)框將不會(huì )顯示任何非法文件。

FileDialog元素將會(huì )通過(guò)讀取files列表屬性來(lái)展示目錄的內容。這些文件將會(huì )作為GridView元素的模型,GridView將通過(guò)代理
將數據元素以網(wǎng)格的形式顯示出來(lái)。代理主要用于處理模型的顯示,我們的文件對話(huà)框僅僅是創(chuàng )建文字處于中心的網(wǎng)格。點(diǎn)擊一
個(gè)文件名將會(huì )導致一個(gè)文件名高亮。當notifyRefresh信號被發(fā)射,FileDialog對話(huà)框就會(huì )被通知重新加載目錄的內容。

現在我們的FileMenu可以連接到相應的動(dòng)作上。saveButton將會(huì )把TextEdit上的文本轉化為目錄的fileContent屬性,然后從文本
輸入框中獲取文件的名稱(chēng),該按鈕會(huì )調用saveFile()函數保存文件。loadButton以類(lèi)似的過(guò)程執行。New按鈕將會(huì )清空TextEdit的內容。
EditMenu下的按鈕會(huì )將copy,paste和selectall這些函數與TextEdit連接起來(lái)。

完成文本編輯器

該應用程序是一個(gè)簡(jiǎn)單的文本編輯器,可以加載和保存文件,并執行簡(jiǎn)單的操作:剪切、復制以及全選等功能。
運行文本編輯器
在運行文本編輯器之前,我們需要將C++代碼編譯為插件。要編譯C++代碼,我們進(jìn)入filedialog目錄,運行qmake命令,然后
使用make或者nmake編譯,這取決于你的平臺。接著(zhù)運行qmlscene打開(kāi)texteditor.qml文件即可。
源代碼在examples/tutorials/gettingStartedQml目錄下。
評論