[QML]事無鉅細開始實踐QML開發(一)什麼是QML,為什麼學習QML,先寫一個簡單的頁面

2023-06-23 06:00:36

[QML]從零開始QML開發(一)什麼是QML,為什麼學習QML,先寫一個簡單的頁面

QML開發和QWidget開發的區別

QML(Qt Meta-Object Language)是Qt提供的一種宣告性語言,用於快速建立使用者介面。相對而言,Qt Widgets是基於C++的桌面應用程式開發框架。

下面是QML和Qt Widgets之間的一些優缺點以及為何Qt公司大力推行QML開發的原因:

優點:

視覺化設計:QML是一種基於標記的語言,使用了層疊樣式表(CSS)類似的語法,使得介面設計變得直觀輕鬆。
跨平臺支援:QML與其他主流作業系統和裝置無關,可以在多個平臺上執行,包括桌面、移動和嵌入式裝置。
快速迭代:QML具有熱過載功能,可以實時編輯和檢視介面的更改,加快了開發和偵錯的速度。
良好的動畫和效果支援:QML通過內建的動畫和效果元件,使得介面的互動和動態效果實現變得簡單。
靈活和可維護性:QML允許將介面元素分解為可重用的元件,使得程式碼結構化,易於拓展和維護。

缺點:

學習曲線:QML需要學習新的語法和概念,相對於傳統的C++開發,可能需要一些時間來適應和掌握。
效能:與原生C++應用程式相比,QML在某些情況下可能會有效能上的損失,尤其是在複雜介面或需要大量渲染的場景中。
Qt公司推行QML開發的原因:

使用者體驗:QML提供了現代化、使用者友好的介面設計能力,可以建立吸引人且互動性強的使用者介面。
多平臺支援:QML通過跨平臺的特性,可以將開發的應用程式輕鬆地移植到不同的作業系統和裝置上,提高了開發效率和程式碼的重用性。
易用性和開發效率:QML的視覺化設計和宣告性語法使得開發者可以更快速地構建和迭代介面,減少了開發週期。

這也是一種真正在Qt上進行前後端分離的方案,這倒是挺新穎的。個人在簡單體驗了一下QML開發之後,感覺QML是一個很類似前端CSS的技術,把頁面變成一個單獨的模組,也算是一種完美貫徹MVC模式的工具吧(畢竟之前還是會有很多人把業務放到介面裡面去寫,而且也會被人瘋狂亂噴)某種意義上來說,這也是一種真正在Qt上進行前後端分離的方案,這倒是挺新穎的。

另外值得一提的點,QML作為一種幾乎是描述性語言的存在,其跨平臺的支援理論上應該顯著好於QWidget的,所以新專案的開發(大概率是要相容多系統)儘量在QML的基礎上開發吧!

這就又相當於是我學了一門新的語言了,但既然已經有了QWidget的開發經驗,再去開發前端html頁面想必難度也不會大到哪裡去,那麼就來看看效果吧

開發準備

作為一名高貴的windows開發,那自然是要使用宇宙第一IDE:Visual Studio 2022 + Qt 5.14.2

為什麼不用Qt 6 ?因為我這臺開發電腦上沒有裝Qt 6 ,不過具體使用起來大差不差。

然後比較重要的一點是,QML本身可能對中文的支援有點問題,也就是說QML中如果出現了中文,可能就會出現亂碼。當然了不止QML中會出現亂碼,在QWidget中也會出現亂碼,不同的是可以在QWidget中使用#pragma characterset("utf8")解決,但是在QML檔案中不允許這樣的語法出現(實際上QML是一套自己的語法),所以只能通過儲存檔案為UTF-8 with BOM的方式來規避掉這種可能出現的問題。

這也是為什麼我們說QML比較適合新專案----因為你也不能保證以前的老專案的程式碼檔案是以UTF8 with BOM格式儲存的,也不可能把以前的老程式碼全部轉換成UTF8 with BOM,這個是比較需要注意的。

至於說怎麼轉,網上教學一大堆,我只說我的做法 : 下載外掛 Format on Save for VS2022(當然了每個vs版本肯定都會有的)

具體方法就是:擴充套件--》管理擴充套件--》聯機--》搜尋並下載Format on Save for VS2022--》下載完成--》VS上方選單欄點選工具--》選項--》Format On Save -->UTF8-->Enable ForceUtf8WithBom 改為True

OK,讓我們開啟我們的第一個專案,怎麼建立的就不說了,反正就是你在建立專案的時候直接建立一個QtQuick專案就可以了,我們來直接看專案內部:

先來看main函數,這個

QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

先不管,這一段是給整個程式設定了一個支援高DPI的模式,這個無所謂

QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
	return -1;

在這段程式碼中,使用QQmlApplicationEngine來載入和執行一個QML介面。

首先,建立了一個QQmlApplicationEngine物件,該物件用於載入和管理QML應用程式。

然後,使用engine.load(QUrl(QStringLiteral("qrc:/main.qml")))語句載入名為"main.qml"的QML檔案。在這裡,使用QUrl::fromLocalFile()函數將檔案路徑轉換為QUrl格式,"qrc:"表示該檔案位於Qt資源(qrc)中。

接下來,通過engine.rootObjects().isEmpty()判斷載入的QML介面是否成功。engine.rootObjects()返回根物件的列表,如果列表為空,則表示載入失敗。

如果載入的QML介面成功,程式繼續執行後續的邏輯。否則,返回-1,可能表示載入失敗或發生錯誤。

簡而言之,這段程式碼的作用是載入並檢查一個QML介面是否成功載入,如果載入成功,則繼續執行其他相關操作。

然後我們雙擊一下這個main.qml檔案,進來看看,內容大概如下:

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5
Window {
	visible: true
	width: 640
	height: 480
	title: qsTr("Hello World")


}

沒錯,就這麼簡單,就是幾句話就表示了一個視窗,沒有那麼多規定複雜的建構函式,訊號,Q_OBJECT宏之類的,而是一個由Qt完全封裝好了的QML檔案

讓我們來編譯執行一下,大概效果就是生成了一個視窗:

讓我們來寫一個按鈕,新增程式碼如下:

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5
Window {
	visible: true
	width: 640
	height: 480
	title: qsTr("Hello World")

	 Button{
		x:100  //設定按鈕的橫座標
		y:100  //設定縱座標
		text:"我是按鈕"   //按鈕標題

		//一個類似JS風格的函數
		function slotAnyway(){
			console.log("slotAnyway")
		}
		//訊號槽連線
		onClicked: {
			slotAnyway()
			console.log("點選")
		}
	}
}

再編譯執行一下:

然後按一下這個按鈕就會彈出對應的提示。onClick是點選函數,至於這個函數是什麼意思,將會在之後的文章中著重講一下,這裡不講訊號槽這些概念。

預覽

寫到這裡,不禁讓我頭皮發麻,因為這裡有一個非常嚴重的問題就是:我怎麼知道現在介面是什麼情況的?之前有一幫B開發就是用純程式碼寫QWidget,而且不能預覽,偵錯起來真的麻煩的我想殺人。

當然了,Qt肯定也想到了這個問題,不然他們也不會一開始就提供.ui給使用者去編輯了,相對的,Qt也肯定提供了一套QML的預覽工具以供開發者呼叫,這個工具就是 :qmlscene.exe,這個工具的位置在你的Qt安裝目錄的指定版本下的bin目錄,比如D:\DevTools\Qt_5.14.2\5.14.2\msvc2017_64\bin\qmlscene.exe

怎麼用呢?其實也簡單,就是直接雙擊qmlscene.exe,然後再選擇指定的.qml檔案就行了

當然了,這肯定有點低能,我們也不可能這麼做。正確的做法是
右鍵main.qml->..開啟方式->瀏覽->找到qmlscene.exe,注意不能設定為預設,否則你就不能編輯這個.qml檔案了,只需要每次預覽的時候雙擊一下就可以了

之後簡單說一下關於QML控制元件、訊號、槽、錨、屬性相關的內容

偵錯

當然了,你肯定會好奇這種程式碼怎麼偵錯,你會好奇地在qml欄位上打上一個斷點然後嘗試偵錯,結果你發現行不通。

當然了,Qt也考慮到了這個問題,當你需要偵錯這個程式的時候,請右鍵專案-》屬性-》Qt Project Settings->QML->Enable QMl Debugging->改為是,這樣之後你在qml檔案中打上的斷點就可以被命中了,當然了這也帶來一個問題,就是當你在之後刪掉這個斷點後,每次偵錯或者啟動這個程式都會告訴你程式命中了斷點但是找不到這個斷點,不過這並不是什麼首要的問題,不是嗎?