PyQt/PySide6快速入門 - 4 QML天氣小程序(a)

上一篇:PyQt/PySide6快速入門 - 3 QML簡介與Qt Creator開發(fā)環(huán)境 - 簡書 (jianshu.com)

本期知識點:

QML項目目錄框架起趾,PathView動畫穷缤,StackView頁面切換佃迄,信號贮泞,transform動畫

天氣小應用介紹:

主界面:各個城市之間可劃動選擇倍靡,也可以直接點圖標選擇叮盘。點擊某個城市開始查詢天氣猜绣。這類操作適合在可穿戴設備上灰殴,比如手表、手環(huán)掰邢。


image.png

子頁面:顯示天氣詳情牺陶。


image.png

上下導航條:“返回”到主界面,返回上一級

項目目錄框架:

/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后臺软棺,以及本地文件權限管理等掺冠。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市码党,隨后出現(xiàn)的幾起案子德崭,更是在濱河造成了極大的恐慌,老刑警劉巖揖盘,帶你破解...
    沈念sama閱讀 206,013評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件眉厨,死亡現(xiàn)場離奇詭異,居然都是意外死亡兽狭,警方通過查閱死者的電腦和手機憾股,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來箕慧,“玉大人服球,你說我怎么就攤上這事〉呓梗” “怎么了斩熊?”我有些...
    開封第一講書人閱讀 152,370評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長伐庭。 經(jīng)常有香客問我粉渠,道長,這世上最難降的妖魔是什么圾另? 我笑而不...
    開封第一講書人閱讀 55,168評論 1 278
  • 正文 為了忘掉前任霸株,我火速辦了婚禮,結(jié)果婚禮上集乔,老公的妹妹穿的比我還像新娘去件。我一直安慰自己,他們只是感情好扰路,可當我...
    茶點故事閱讀 64,153評論 5 371
  • 文/花漫 我一把揭開白布尤溜。 她就那樣靜靜地躺著,像睡著了一般幼衰。 火紅的嫁衣襯著肌膚如雪靴跛。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,954評論 1 283
  • 那天渡嚣,我揣著相機與錄音梢睛,去河邊找鬼肥印。 笑死,一個胖子當著我的面吹牛绝葡,可吹牛的內(nèi)容都是我干的深碱。 我是一名探鬼主播,決...
    沈念sama閱讀 38,271評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼藏畅,長吁一口氣:“原來是場噩夢啊……” “哼敷硅!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起愉阎,我...
    開封第一講書人閱讀 36,916評論 0 259
  • 序言:老撾萬榮一對情侶失蹤绞蹦,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后榜旦,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體幽七,經(jīng)...
    沈念sama閱讀 43,382評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,877評論 2 323
  • 正文 我和宋清朗相戀三年溅呢,在試婚紗的時候發(fā)現(xiàn)自己被綠了澡屡。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 37,989評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡咐旧,死狀恐怖驶鹉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情铣墨,我是刑警寧澤室埋,帶...
    沈念sama閱讀 33,624評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站踏兜,受9級特大地震影響词顾,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜碱妆,卻給世界環(huán)境...
    茶點故事閱讀 39,209評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望昔驱。 院中可真熱鬧疹尾,春花似錦、人聲如沸骤肛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽腋颠。三九已至繁成,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間淑玫,已是汗流浹背巾腕。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評論 1 260
  • 我被黑心中介騙來泰國打工面睛, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人尊搬。 一個月前我還...
    沈念sama閱讀 45,401評論 2 352
  • 正文 我出身青樓叁鉴,卻偏偏與公主長得像,于是被迫代替她去往敵國和親佛寿。 傳聞我的和親對象是個殘疾皇子幌墓,可洞房花燭夜當晚...
    茶點故事閱讀 42,700評論 2 345

推薦閱讀更多精彩內(nèi)容