上一篇:PyQt/PySide6快速入門 - 3 QML簡介與Qt Creator開發(fā)環(huán)境 - 簡書 (jianshu.com)
本期知識點:
QML項目目錄框架起趾,PathView動畫穷缤,StackView頁面切換佃迄,信號贮泞,transform動畫
- 參考:Qt官方Example: Qt\Examples\Qt-6.3.0\quickcontrols2\wearable\
- 我的源碼(更新中):https://github.com/kevinqqnj/qml_weather 族扰。文中只是代碼片段锌订,大家可導入我的完整代碼來運行
- 演示視頻:Qt QML+PySide天氣小程序 (zhihu.com)
天氣小應用介紹:
主界面:各個城市之間可劃動選擇倍靡,也可以直接點圖標選擇叮盘。點擊某個城市開始查詢天氣猜绣。這類操作適合在可穿戴設備上灰殴,比如手表、手環(huán)掰邢。
子頁面:顯示天氣詳情牺陶。
上下導航條:“返回”到主界面,返回上一級
項目目錄框架:
/images === 圖片
/js === js腳本
main.py === Python主程序
main.qml === QML主入口
HomePage.qml === Homepage主界面
NaviButton.qml === 組件:導航返回
WeatherPage.qml === 天氣頁面
weather_qml.qrc === 資源文件
步驟:
使用Qt Creator辣之,新建一個Qt for Python - Quick應用掰伸,選PySide6
App主程序 main.py
由于使用了Qt.labs.settings,這里需要添加兩行參數(shù):QCoreApplication.setXXX
創(chuàng)建qml engine怀估,引用QML主文件 main.qml
if __name__ == "__main__":
os.environ["QML_XHR_ALLOW_FILE_READ"] = "1"
QCoreApplication.setApplicationName("Weather App");
QCoreApplication.setOrganizationName("QtProject");
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
engine.load(os.fspath(Path(__file__).resolve().parent / "main.qml"))
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec())
QML主入口:main.qml
ApplicationWindow 自帶header/footer/background屬性狮鸭,方便設計應用框架
Settings組件:可以存儲用戶的選擇合搅,也可以當作全局變量來訪問,如:settings.cityId
header和footer: 放置NavButton歧蕉,用于導航灾部、返回:onClicked: stackView.pop()
StackView:堆疊頁面組件,可以讓用戶進入子頁面惯退,以及返回前一頁面:push赌髓,pop方法
初始頁面為:HomePage
HomePage有 signal: lauched,在這里可以監(jiān)聽到
ApplicationWindow {
id: window
visible: true
width: 450
height: 800
title: qsTr("小天氣 App")
property string page
Settings {
id: settings
property int cityId
}
property alias settings: settings // 全局變量
background: Image {
source: "images/background-light.png"
}
header: NaviButton {
id: homeButton
edge: Qt.TopEdge
enabled: stackView.depth > 1
imageSource: "images/home.png"
onClicked: stackView.pop(null)
}
footer: NaviButton {
id: backButton
edge: Qt.BottomEdge
enabled: stackView.depth > 1
imageSource: "images/back.png"
onClicked: stackView.pop()
}
StackView {
id: stackView
focus: true
anchors.fill: parent
initialItem: HomePage { // Qt6必須以function方式響應signal
onLaunched: (_) => stackView.push("WeatherPage.qml")
}
}
}
創(chuàng)建主界面UI:HomePage.qml
定義信號:signal launched(int cityId)
使用PathView催跪,動態(tài)放置所有可選的model item(城市圖標)锁蠕,到一條自定義路徑上
Path :自定義路徑。PathLine是畫一條直線懊蒸,PathArc畫圓弧荣倾。里面可以用PathAttribute定義每個節(jié)點的特殊屬性。我畫的路徑是從中心先往左骑丸,然后向上半圓移動到最右邊舌仍,最后回到中心。
Delegate:設置每個子元素的渲染方法者娱。這里用RoundButton 渲染抡笼。監(jiān)聽onClicked事件苏揣,發(fā)送信號黄鳍,并存儲cityId到全局變量中
Text組件:顯示當前選擇城市的名字
可以用鼠標左右滑動,也可以直接點擊某個城市圖標平匈。然后再點中間框沟,就會進入到子頁面(天氣詳情)
PathView {
id: circularView
signal launched(int cityId)
readonly property int cX: width / 2
readonly property int cY: height / 2
readonly property int itemSize: size / 3
readonly property int size: Math.min(width-80, height)
readonly property int radius: size / 2.4 //畫Path圓的半徑,越大圖標離得越遠
snapMode: PathView.SnapToItem
anchors.fill: parent
model: ListModel {
ListElement {
name: qsTr("南京")
icon: "images/nanjing.png"
cityId: 1
}
增炭。忍燥。。
ListElement {
name: "香港"
icon: "images/hongkong.png"
cityId: 7
}
}
delegate: RoundButton {
width: itemSize
height: itemSize
property string name: model.name //必須要設置prop隙姿,不然其它Component不能訪問currentItem.xxx
property string cityId: model.cityId
icon.width: width*.7
icon.height: width*.7
icon.source: model.icon
opacity: PathView.itemOpacity
background: Rectangle {
radius: width / 2
border.width: 3
border.color: parent.PathView.isCurrentItem ? "#41cd52" : "#aaaaaa"
}
onClicked: {
console.log(`currIndex=${circularView.currentIndex}, index=${index}, id: ${name}`)
if (PathView.isCurrentItem){
settings.cityId = cityId
circularView.launched(cityId) }
else
circularView.currentIndex = index
}
}
path: Path {
startX: cX; startY: cY
PathAttribute {name: "itemOpacity"; value: 1.0}
PathLine { x: cX/5; y: cY}
PathAttribute {name: "itemOpacity"; value: .2}
PathArc {
x: cX*1.8
y: cY
radiusX: cX/1.2
radiusY: circularView.radius/1.5
useLargeArc: true
direction: PathArc.Clockwise
}
PathAttribute {name: "itemOpacity"; value: .2}
PathLine { x: cX; y: cY }
PathAttribute {name: "itemOpacity"; value: .1}
}
Text {
id: nameText
property Item currentItem: circularView.currentItem
visible: currentItem ? currentItem.PathView.itemOpacity === 1.0 : 0
text: currentItem ? currentItem.name : ""
}
}
NavButton.qml 子組件
你的主QML文件梅垄,會自動調(diào)用當前目錄下的所有*.qml文件,作為子組件引入输玷,然后可直接使用它队丝,比如NavButton。當然欲鹏,也可以用import命令來手動引入子模塊机久、js代碼等
添加自定義屬性imageSource:父組件可以通過它來對子組件的屬性賦值,imageSource: "images/xxx.png"赔嚎,上下圖標選擇對應的.png文件
添加了動畫Behavior on y { NumberAnimation { } :當enabled(父組件設置)時膘盖,監(jiān)聽y值變化胧弛,然后動態(tài)自動改變值從初始值到目標值,達到動畫顯示和隱藏的效果侠畔,默認動畫時長250ms
AbstractButton {
id: button
property int edge: Qt.TopEdge
property alias imageSource: image.source
contentItem: Image {
id: image
fillMode: Image.Pad
sourceSize { width: 40; height: 40 } // ### TODO: resize the image
}
background: Rectangle {
height: button.height * 4
width: height
radius: width / 2
anchors.horizontalCenter: button.horizontalCenter
anchors.top: edge === Qt.BottomEdge ? button.top : undefined
anchors.bottom: edge === Qt.TopEdge ? button.bottom : undefined
}
transform: Translate {
Behavior on y { NumberAnimation { } }
y: enabled ? 0 : edge === Qt.TopEdge ? -button.height : button.height
}
}
下一篇:會講天氣詳情頁面的設計结缚,包含調(diào)用javascript,發(fā)送信號給Ptyhon后臺软棺,以及本地文件權限管理等掺冠。