このガイドでは、Qt と QML を使用して Seeed reTerminal 用の天気アプリを作成する方法を紹介します。玄関の廊下にある reTerminal を想像してみてください。画面をちらりと見るだけで、今後数時間の天気がどうなるか、傘が必要かどうか、自転車に乗っているときに向かい風が吹くかどうか、または天気が悪いかどうかを知ることができます。晴れて晴れるでしょう。このチュートリアルは、前回の記事で構築した reTerminal Yocto boot2qt ディストリビューションに基づいて構築されており、Qt 6 を使用しています。Qt は C++ フレームワークですが、この Weather アプリはほとんど QML のみを使用します。私は QML だけを使用してガイドをよりアクセスしやすくしています。また、すべてを C++ で行うことに慣れているため、QML を回避するのも楽しいものです。
これは、基本を設定するガイドのパート 1 です。これには、QML を介したネットワーキング、QML での Open Meteo JSON 天気 API の解析、および QML での天気コードの表示が含まれます。 Qt や C++ を初めて使用する場合でも、心配する必要はありません。QML は GUI を定義するための宣言型言語ですが、これには JavaScript が含まれています。つまり、インターフェースを簡単にレイアウトし、JavaScript の一部をいくつかの面倒な作業に使用することができます。この場合、これはネットワーク アクティビティと JSON 解析になります。このガイドの最後には、JSON API 天気コードをテキスト表現に変換し、reTerminal で実行されている現在の気温を表示する基本画面が表示されます。
これは、私のデスクトップで実行されているパート 1 の最終結果の写真です:
パート 2 では、ユーザー インターフェースのスケーリング (PC と reTerminal の両方で実行するため)、永続的な設定、ロケーション ピッカー、更新タイマー、数時間先を含むより多くの気象要素を使用して WeatherTerminal を拡張し、さまざまなレイアウトなどのより高度な QML の概念をカバーします。 、アンカー要素、条件、モデル、およびプロパティ。 reTerminal には物理的なキーボードがないため、パート 2 には QtVirtual キーボードも含まれていますが、場所を入力したくありません。
パート 2 はまだ終わっていません。終わったら、ここにリンクします。
完全な開示:Seeed から連絡があり、いくつかの記事と引き換えにこの reTerminal が送られてきました。金銭的な支払いは関係なく、Seeed は公開前にこの記事をレビューしていません。公式サポートについては、Seeed wiki にアクセスしてください。
パート 1 の完全なソース コードは、私の github にあります
reTerminal とは
reTerminal は、将来に備えたヒューマン マシン インターフェース (HMI) として販売されています。 ThereTerminal は、1.5GHz で動作するクアッドコア ARM Cortex-A72 CPU である Raspberry Pi Compute Module 4 (cm4) と、解像度 1280x720 の 5 インチ IPS 容量性マルチタッチ スクリーンを搭載しています。 4 GB の RAM と 32 GB の eMMC ストレージが組み込まれています (拡張不可)。デュアルバンド 2.4GHz/5GHz Wi-Fi および Bluetooth 5.0 BLE によるワイヤレス接続を備えています。
reTerminal はこちらで購入できます。現在の価格は 195 米ドルです。 これには Compute Module 4 が含まれます。
ハードウェアと機能のより包括的な概要については、別の記事を参照してください。
開始前に必要なこと
Yocto boot2qt のセットアップに関する以前の記事に従ってください。
この Qt アプリは、reTerminal で提供されている Raspbian OS では動作しません。これを書いている時点では、使用している Qt バージョンは、その Debian バージョンで出荷されたものよりも新しいためです。 Qt 6.2 を自分でコンパイルすることもできますが、それはこのガイドの範囲外です。
次に、Qt Creator と Qt バージョン 6.2 がインストールされていることを確認します。 Yoctoboot2qt の記事には、reTerminal 用にクロスコンパイルする必要がある SDK の手順が記載されています。
Qt Creator で、別のガイドで説明されているようにキットを構成し、デプロイ先のデバイスとして reTerminal を構成します。すべて完了したら、戻って続行してください。
デスクトップで WeatherTerminal アプリを実行するだけの場合は、reTerminal 用に yocto boot2qt をセットアップする必要はなく、クロスコンパイルも必要ありませんが、Qt Creator と Qt 6.2 をインストールする必要があります。
これは優れた QML と Qt のガイドですが、このガイドの目的は reTerminal 用のアプリを構築することなので、そのことを心に留めておいてください。
ファイル -> 新しいプロジェクト
開発者として最も素晴らしいことの 1 つは、File -> New
Project
を実行した瞬間です。 .白紙の状態で、あなたの世界を描く準備ができています。クラフト、レガシーなどはありません。ですから、この瞬間を楽しんでください。 Qt Creator (私はバージョン 7 を使用しています) を起動し、魔法のステップを実行します。
必ず Qt Quick (QML) アプリケーションを選択し、qmake
を選択してください。 ビルドシステムとして、Qt の最小バージョンを 6.2 に設定してください。通常の Qt6 キットと、前の記事で作成した Yocto SDK 提供のキットの両方を選択します。
スワイプ タブ レイアウト
まず、2 つのタブを持つレイアウトを設定します。タブバーをクリックするか、左右にスワイプして別のタブに移動できます。
1 つのタブはメインの天気情報ページで、もう 1 つのタブは設定用です。多くの設定があるわけではありませんが、基本的なレイアウトの足場は後で変更するよりも簡単です。
左側のファイル エクスプローラーで、Resources
に移動します。 、 qml.qrc
、 /
ファイル main.qml
を開きます
基本的な ApplicationWindow
があるはずです 1 つまたは複数の import
ステートメント。 QML ファイルの構造は単純です。QML ファイルには、そのコンポーネントの動作とプロパティを定義する単一の最上位アイテムがあります。
たとえば、WeatherButton.qml
という名前の新しい QML ファイルを作成すると、 、そのアイテムを ApplicationWindow
内に配置できます WeatherButton
{}
と書くことで .
この例では、タブレイアウトを構築するためにいくつかのコンポーネントを含めます。 Qt QuickControls を使用するには、最初に次の行を先頭に追加します。
import QtQuick.Controls
Qt 5 ではインポートするバージョン番号を指定する必要がありましたが、Qt6 では不要になりました。
width:
を変更します と height:
プロパティ値を 1280 および 720 に変更し、reTerminal の画面サイズを調整します。タイトルに何か良いものを入れて、ApplicationWindow
内のそれ以上のコンテンツをすべて削除します 成分。
次の行を追加します:
SwipeView {
id: swipeView
anchors.fill: parent
currentIndex: tabBar.currentIndex
}
footer: TabBar {
id: tabBar
currentIndex: swipeView.currentIndex
TabButton {
text: "Weather"
font.pixelSize: 30
}
TabButton {
text: "Settings"
font.pixelSize: 30
}
}
CTRL+R (または再生ボタンのように見える緑色の三角形) を押して、作成した驚異を見てください:
また、reTerminalで実行してみてください。 QML アプリをローテーションするために Wayland + Weston セットアップを使用している場合は、QtCreator の環境に以下を追加します。
Yocto デバイス キットとリモート デバイスを選択し、Play
を押します。 再ターミナルでコンパイルして実行するには:
タブ付きの基本的な空白の状態を実行している reTerminal の写真を次に示します。
SwipeView
にはまだ実際のコンテンツはありません。
QML は簡単で、C++ コードは必要なく、タブ付きのアプリが既にあると言っていました。
SwipeView
から始めて、これまでに行ったことを説明します :
-
id: swipeView
:特定のオブジェクトを識別し、他のオブジェクトから参照できるようにするテキスト ID。この ID は小文字またはアンダースコアで始まる必要があり、文字、数字、およびアンダースコア以外の文字を含めることはできません。 -
anchors.fill: parent
:swipeview をその親 (ウィンドウ) に固定し、効果的にサイズを変更してウィンドウ全体を埋めます。 -
currentIndex: tabBar.currentIndex
:プロパティ バインディング。プロパティ値currentIndex
の場合はいつでもtabBar
の 更新すると、QML エンジンはこのプロパティの値も自動的に更新します。タブのスワイプとクリックを効果的に結合します。
プロパティ バインディングは、QML の強みの 1 つです。この場合、プロパティ バインディングがないと、タブ ボタンをクリックするたびにスワイプ ビュー インデックスを変更し (実際にはスワイプ ビューを更新する)、その逆も同様にする関数を作成する必要があります。
アンカーについては、パート 2 で詳しく説明します。今のところ、それらを一種の磁石と考えることができます。アイテムの片側が別のアイテムの片側に固定されています。ただし、パフォーマンス上の理由から、親アイテムまたは兄弟アイテムのみ。
次は footer: TabBar {}
です . footer
実際には ApplicationWindow
のプロパティです プロパティは Item
を取ります その値として、TabBar
全体を配置できるのはそのためです。 その中。
Items
QtQuick
からの視覚的なものです モジュール。クイックはQt User Interface Creation Kit
の略です .
tabBar には独自の id:
があります プロパティであり、2 つの Items
が含まれています 内部、2 つの TabButtons
、独自のプロパティもあります:
TabButton {
text: "Weather"
font.pixelSize: 30
}
text:
ボタンに表示されるテキストと font.pixelSize
が含まれています ご想像のとおり、フォントのピクセル単位のサイズです。
TabBar
のせいで 画面上で独自のレイアウト (子要素の配置) を行う場合、x:
を指定する必要はありません。 、 y:
または anchors:
ボタンの内側。 TabBar
隣り合っていることを確認してください。
TabBar
のボタンをクリックすると 、currentIndex
プロパティの変更。 Settings
をクリックすると 1
になります .プロパティ currentIndex
のため currentIndex
にバインドされています swipeView
のプロパティ 、そのスワイプビューのcurrentIndex
1
にもなります .実際、これは SwipeView
になります 現在のアイテムを、その中の 2 番目の子アイテムに変更します (配列は 0 から始まることに注意してください)。
Qt を初めて使用する場合、これは単純な例に凝縮された多くの情報です。いろいろ試してみて、オートコンプリートがプロパティに提供するものを見て、それをいじってみてください。テキストの色を red
にしてみてください 例えば。
タブをページで埋める
タブができたので、便利なものを入力してみましょう。 /
を右クリック qml.qrc
内のフォルダ SettingsPage.qml
という名前の新しい QML ファイルを作成します。 :
次の内容を貼り付けます:
import QtQuick
import QtQuick.Controls
Page {
id: root
width: 1240
height: 640
header: Label {
text: "Settings"
font.pixelSize: 50
}
}
これは、ヘッダーのみの空のプレースホルダー ページです。 footer:
と同じ ApplicationWindow
のプロパティ 、header:
プロパティは Item
を取ります 値として、この場合は Label
です . Button
の可能性もあります またはあなたが好きなもの。 Page
コントロールはレイアウトを処理し、header:
を確認します Item
ページの上部にあります。
main.qml
で 、 SwipeView
内 、この新しいコンポーネントを追加します:
SwipeView {
[...]
SettingsPage {}
}
Play を押してテストすると、ヘッダー テキスト Settings
が表示されます。 、天気タブ。なんで? SwipeView
子項目が 1 つだけあり、自動的に index
を取得します 番号 0。
別のファイルに対して新しい QML ファイルの作成を繰り返し、これに WeatherPage.qml
という名前を付けます
SettingsPage.qml
と同じ内容を追加 ファイルですが、Label
を変更してください Weather
と言う SwipeView
に追加します main.qml
で 、 SettingsPage
のすぐ上 :
SwipeView {
[...]
WeatherPage {}
SettingsPage {}
}
[再生] を押してもう一度試してください。Weather
が表示されます。 開くタブとして。 SwipeView
以来、右または左にスワイプすることもできます に子アイテムが追加されました。スワイプすると、タブ バーの現在アクティブなタブも変更されます。
Open Meteo API の解析
私が Open-Meteo API を選択したのは、API キーやユーザー登録が不要で、オープン ソースまたは非営利目的での使用が無料であるためです。きちんとした JSON API を提供し、LAT と LON を渡すと、予測が得られます。
アプリでは次の URL を使用しますが、何らかの理由で使用できない場合は、こちらのサイトの (静的) ミラーも使用できます。後者には明らかに現在の予測が含まれていませんが、正しい JSON 形式が提供されます。
WeatherPage.qml
内で独自のプロパティを定義することから始めましょう 、 width
のすぐ下 と height
:
property var parameters: undefined
property double latitude: 52.3738
property double longitude: 4.8910
最後の 2 つは自明ですが、最初の 1 つ (parameters
) は、デコードされた JSON を保持します。 var
タイプは anything
です QML を入力します。プロパティが保持する型がわかっている場合は、それを指定する方が高速です (string
var
の代わりに 例えば)。 var
type は、通常の JavaScript 変数と同等です。たとえば、var プロパティには、数値、文字列、オブジェクト、配列、および関数を格納できます。解析された JSON は QJSValue
型になるため、 var
と一致するより具体的な QML タイプはありません。
カスタム プロパティを追加したら、関数を追加します。これは通常の JavaScript 関数ですが、次のように QML プロパティにアクセスできます:
function getJson(latitude, longitude) {
var xmlhttp = new XMLHttpRequest()
var url = "https://api.open-meteo.com/v1/forecast?latitude=" + latitude
+ "&longitude=" + longitude + "&hourly=temperature_2m,relativehumidity_2m,apparent_temperature,weathercode,windspeed_10m,winddirection_10m&daily=weathercode,temperature_2m_max,temperature_2m_min,sunrise,sunset¤t_weather=true&timezone=Europe%2FAmsterdam"
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState === XMLHttpRequest.DONE
&& xmlhttp.status == 200) {
root.parameters = JSON.parse(xmlhttp.responseText)
}
}
xmlhttp.open("GET", url, true)
xmlhttp.send()
}
以前に JavaScript を使用したことがある場合、突出している唯一の点は次のとおりです。
root.parameters = JSON.parse(xmlhttp.responseText)
JavaScript に慣れていない場合、この関数はコールバック メソッドを使用して API URL に GET 要求を送信します。コールバック メソッドは、GET リクエストが正しく終了したかどうかを確認し、終了した場合は JSON 応答を解析し、結果を QML root.parameters
に割り当てます。 財産。 root
id:
です Page
の 、QMLエンジンには複雑なスコープルールがありますが、今のところ、変数をプロパティ parameters
に割り当てる必要があることを知っているだけで十分です SettingsPage
ではなく、このファイルで そのページにも id:
がありますが、ファイル root
の .別のファイル、別のコンテキスト。
この JavaScript メソッドは等号 (=
) を使用していることに注意してください。 ) ではなく、コロン (:
) を使用して、プロパティに値を割り当てます。 QML コロン (:
) プロパティ バインディング、等号 (=
) を作成します。 ) ではない。 width =
height
を実行する場合 JavaScript メソッド内。これはプロパティ バインディングではなく、単なる代入です。 height
の場合 後で変更、width
しない。重要な違いですが、今のところ関係ありません。
このメソッドを呼び出すボタンを追加しましょう。プロパティの下に、以下を追加します:
Button {
id: refreshButton
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.margins: 5
text: "Update Weather"
font.pixelSize: 30
onClicked: getJson(root.latitude, root.longitude)
}
2 つの anchors.
ボタンを左下に表示し、周囲に少し余白を付けます (すべての側面に)。 onClicked
プロパティは、Page
のプロパティとして定義した緯度と経度の 2 つのパラメータを使用して JavaScript メソッドを呼び出します。 .
Play を押してコンパイルして実行すると、ボタンは機能しますが、結果を見ることができません。プロパティ parameters
デコードされた JSON がありますが、まだ何もしていません。正しく実行したことを確認するために、コンソールにログインしてみましょう。 Button
の下 、以下を追加:
onParametersChanged: console.log(root.parameters['current_weather']['weathercode'])
コンパイルして実行し、更新ボタンを押すと、コンソール ログに次のように表示されます:
qrc:/WeatherPage.qml:30: TypeError: Cannot read property 'current_weather' of undefined
qml: 3
最初のエラーは問題ありません。今のところ無視できます。プロパティが宣言されると、空に初期化され、変更されたシグナルが発生しますが、記述した onChanged 関数はパラメーターが空かどうかをチェックしません。
2 行目 (qml: 3
) は実際の weathercode
です JSON API から。
ひとときを楽しんでください。 C++ コードをまったく記述せずに、ネットワーク Web サービスから JSON API を取得するタブ バーとボタンを備えたクロス プラットフォーム アプリを作成しました。繰り返しますが、このガイドで QML だけを使用している理由は、非常に簡単だからです。
onParametersChanged:
の舞台裏 行は、changed
のときに呼び出されるスロット (シグナル ハンドラー) です。 信号は parameters
から発射されます 変数。 Qt には、シグナルとスロットと呼ばれる別の非常に強力な概念があります。これは、オブザーバー デザイン パターンまたは pub-sub のようなものですが、ステロイドと C++ タイプ セーフです。これ以上説明するつもりはありません。シグナルとスロットについてだけ本を書くことができます。興味があれば、Qt ドキュメントをチェックしてください。
すべてのプロパティは、カスタムのものも含めて changed
を持っています 信号、QML エンジンがそれを作成します。そのシグナルは、QML プロパティの値が変更されると自動的に発行されます。このタイプの信号は property change signal
です これらのシグナルのシグナルハンドラは、onPropertyChanged
の形式で記述されます。 、ここで Property
最初の文字を大文字にしたプロパティの名前です。
console.log()
onParametersChanged
に割り当てた関数 スロット (シグナル ハンドラー) は、JSON オブジェクト
['current_weather']['weathercode']
の内容を出力します。 .
WeatherCode の解析
ボタンをクリックするだけで JSON API と対話できるようになったので、今度はその API を解析します。 Clear Sky
のような気象条件の標準数値形式である現在の WeatherCode から始めます。 または Thunderstorm
.
コードは Open-Meteo API ページに書かれており、より包括的な記事は noaa.gov サイトにあります。
テキスト出力の横に、天気コードの変更に応じて変化する素敵なアイコンを追加します。
前と同じように新しい QML ファイルを作成し、WeatherCode.qml
という名前を付けます。 以下を貼り付けます:
import QtQuick
Item {
id: root
property var parameters: undefined
}
WeatherPage.qml
で 、この新しいコンポーネントを Button
の上に追加します 以前に追加しました:
WeatherCode {
id: weatherCode
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
parameters: root.parameters
}
anchors
このコントロールをページの左上に配置し、右に伸ばします。後でコントロール自体で高さを定義します。コントロールに幅/高さまたはアンカーがない場合、表示されません。 parameters
を渡します WeatherPage
の WeatherCode
まで .これはプロパティ バインディングなので、Update
をクリックすると ボタン、WeatherCode
コントロールも新しく更新された parameters
を取得します .
Qt プロジェクト フォルダー内に、icons
という名前の新しいフォルダーを作成します。 次の svg
をダウンロードします FontAwesome.com
からのファイル :
- circle-question-solid.svg
- clock-solid.svg
- cloud-rain.svg
- cloud-showers-heavy-solid.svg
- cloud-showers-water-solid.svg
- cloud-sun-solid.svg
- poo-storm-solid.svg
- レインボー ソリッド.svg
- smog-solid.svg
- snowflake-solid.svg
- sun-solid.svg
- 温度半固体.svg
- 温度-高-固体.svg
- 温度-低固体.svg
- wind-solid.svg
これらはすべて font awesome free の一部であり、CC-BY-4.0 ライセンスです。
Qt Creator で、qml.qrc
を右クリックします。 サイドバーのファイルを開き、Add
existing files
をクリックします。 . icons
でダウンロードしたすべてのアイコンを選択します
新しい Image
を追加 WeatherCode.qml
への制御 ファイル、プロパティの下:
Image {
id: weatherCodeIcon
source: root.parameters ? weathercodeToIcon(
root.parameters['current_weather']['weathercode']) : "qrc:icons/circle-question-solid.svg"
asynchronous: true
anchors.top: parent.top
anchors.left: parent.left
anchors.margins: 5
width: 90
height: width
}
ここまでで、QML 構文に慣れる必要があります。高さは、幅、anchors
へのプロパティ バインドです。 これを左上に配置し、その周りに少し余白を置きます。 asynchronous
プロパティは、この画像の読み込み中にブロックしないように QML エンジンに指示します。 1 つの画像ではボトルネックにはなりませんが、より多くの画像を使用すると、すべての画像を非同期でロードする理由がすぐにわかります (UI がブロックされ、使用できなくなり、フリーズするため)。
source:
プロパティはより複雑で、広く使用されている QML の概念である ternary if
を紹介します。 声明。 root.parameters
の場合 満たされています(not undefined
)、その後、疑問符 (?
) の後にあることを実行します。 )。そうでない場合は、コロン (:
) の後にあることを実行します。 )。これは (疑似コードで) 次のように書くこともできます:
if(root.parameters !== undefined); then
source = weathercodeToIcon(root.parameters['current_weather']['weathercode'])
else
source = "qrc:icons/circle-question-solid.svg"
parameters
を定義しました undefined
として Update
をクリックしない限り、 ボタンをクリックすると、疑問符アイコンが表示されます。 update
を呼び出す場合 関数、parametersChanged
シグナルが発生し、このプロパティ バインディングが再評価されます。
weathercodeToIcon()
関数には次のコードが含まれています。このファイルのプロパティのすぐ下に貼り付けます:
function weathercodeToIcon(weathercode) {
switch (weathercode) {
case 0:
return "qrc:icons/sun-solid.svg"
case 1:
case 2:
case 3:
return "qrc:icons/cloud-sun-solid.svg"
case 45:
case 48:
return "qrc:icons/smog-solid.svg"
case 51:
case 53:
case 55:
case 56:
case 57:
case 61:
case 80:
return "qrc:icons/cloud-rain.svg"
case 63:
case 66:
return "qrc:icons/cloud-showers-solid.svg"
case 65:
case 67:
return "qrc:icons/cloud-showers-water-solid.svg"
case 71:
case 73:
case 75:
case 77:
case 85:
case 86:
return "qrc:icons/snowflake-solid.svg"
case 81:
case 82:
return "qrc:icons/cloud-showers-heavy-solid.svg"
case 95:
case 96:
case 99:
return "qrc:icons/poo-storm-solid.svg"
default:
return "qrc:icons/rainbow-solid.svg"
}
}
ご覧のとおり、特別なことは何もありません。ただの大きな switch ステートメントです。一連の気象コード値ごとに、異なるアイコンを返します。
画像の横で、解析された天気コード テキストの上に、小さなヘッダーが必要です。それを追加して、これを Image
の上に貼り付けます :
Text {
id: weatherHeaderText
text: "Current Weather"
anchors.top: parent.top
anchors.left: weatherCodeIcon.right
anchors.leftMargin: 20
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignTop
font.pixelSize: 18
}
anchors.left: weatherCodeIcon.right
という新しいものがあります .つまり、テキスト オブジェクトの左側をアイコンの右側に固定する必要があります。 leftMargin
を少し追加 それを美しくするために、あなたは完了です。これで、アイコンをどこに配置しても、そのすぐ隣に常にこのテキストが表示されます。アイコンを移動した場合、x:
を手動で更新する必要はありません または y:
Text
の 、すべて自動的に行われます。
ファイルの先頭、id:
のすぐ下 、height
の新しいプロパティを追加します このコントロールの:
Item {
id: root
height: weatherCodeIcon.height
[...]
このコントロール全体を imageicon と同じ高さにする別のプロパティ バインディング。 WeatherCode
を固定しました WeatherPage
で top
,left
と right
、ただし bottom
ではありません .高さを設定しないと、アイテムが見えなくなります。
[再生] を押して、コードを実行します。 Update
をクリックします ボタンとアイコンがクエスチョン マークから、weathercodeToIcon
でマップした現在の天気コードに変わるはずです。 switch
ステートメント:
天気コード コントロールを終了するために、現在の天気テキストも追加しましょう。 weathercodeToIcon
とほぼ同じ 関数、weathercodeToText
を作成します 関数、別の大きな switch
.他の関数の下に追加します:
function weathercodeToText(weathercode) {
switch (weathercode) {
case 0:
return "Clear sky"
case 1:
return "Mainly clear"
case 2:
return "Partly cloudy"
case 3:
return "Overcast"
case 45:
return "Fog"
case 48:
return "Fog (Depositing rime)"
case 51:
return "Light Drizzle"
case 53:
return "Moderate Drizzle"
case 55:
return "Dense Drizzle"
case 56:
return "Light Freezing Drizzle"
case 57:
return "Dense Freezing Drizzle"
case 61:
return "Slight Rain"
case 63:
return "Moderate Rain"
case 65:
return "Heavy Rain"
case 66:
return "Light Freezing Rain"
case 67:
return "Heavy Freezing Rain"
case 71:
return "Slight Snowfall"
case 73:
return "Moderate Snowfall"
case 75:
return "Heavy Snowfall"
case 77:
return "Snow grains"
case 80:
return "Slight Rainshower"
case 81:
return "Moderate Rainshower"
case 82:
return "Violent Rainshower"
case 85:
return "Slight Snowshowers"
case 86:
return "Heavy Snowshowers"
case 95:
return "Thunderstorm"
case 96:
return "Thunderstorm with slight hail"
case 99:
return "Thunderstorm with heavy hail"
default:
return "Rainbows!"
}
}
Image
の下 、新しい Text
を追加します コントロール:
Text {
id: weatherCodeText
text: root.parameters ? weathercodeToText(
root.parameters['current_weather']['weathercode']) : "Loading weather, please press update"
anchors.bottom: weatherCodeIcon.bottom
anchors.left: weatherCodeIcon.right
anchors.leftMargin: 20
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignBottom
font.pixelSize: 50
wrapMode: Text.WordWrap
}
このコントロールが行うことは、もはや驚くべきことではありません。私たちは anchor
アイコン画像のすぐ隣にあり、 parameters
の場合 定義されている場合は、weathercodeToText
に渡します 現在の天気を返す関数。パラメータがまだない場合は、Loading Weather, please press update
と表示されます .
完全なコードは私の GitHub で見つけることができるので、自分の QML ファイルと私の QML ファイルを比較して、正しく従ったかどうかを確認できます。
天気コードの解析が完了したので、引き続き気温に進みましょう。これは単なる数値であるため、大規模な JavaScript 解析メソッドを除いて、この部分と非常によく似ています。
温度
以前と同じように新しい QML ファイルを作成し、Temperature.qml
という名前を付けます。 .空の Item
を貼り付けます テンプレート。 height
を含めています そしてparameters
、これは前のパートで既に説明したためです:
import QtQuick
Item {
id: root
height: temperatureIcon.height
property var parameters: undefined
}
このコントロールを WeatherCode のように見せたいので、これには同じレイアウト、アイコン、および小さなヘッダー テキストがあります。今回はアイコンに違いがないので、JSON 解析はありません。 parameters
の下に貼り付けます :
Image {
id: temperatureIcon
source: "qrc:icons/temperature-half-solid.svg"
asynchronous: true
anchors.top: parent.top
anchors.left: parent.left
anchors.margins: 5
width: 90
height: width
}
Text {
id: apparentTemperatureText
text: "Apparent Temperature"
anchors.top: parent.top
anchors.left: temperatureIcon.right
anchors.leftMargin: 20
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignTop
font.pixelSize: 18
}
このガイドでこれまで行ったことがないことは何もないため、上記の QML コードはおなじみのはずです。
必要に応じて、現在の見かけの温度を解析し、設定された量よりも高いまたは低い場合は、別の温度アイコンを表示できます。摂氏 10 度未満の場合はすべて、温度-低-固体.svg アイコンを表示し、20 度を超えるすべての場合は、温度-高-固体.svg および温度-半固体.svg の間のすべてを表示します。どのようにするかは読者の練習問題として残しておきますが、前のweathercodeのパラグラフの例を使えば、難しいことではありません.
通常の温度ではなく見かけの温度を選択したのは、主に JSON API が current_weather
でこの変数を公開していないためです。 JSON 構造なので、hourly
を解析する必要があります JSON の一部です。そうでなければ、この例はウェザーコードとほとんど同じになり、退屈になります。もちろん、見かけの温度は、reTerminal を廊下に吊るして、どんなコートを着るかを知るのに役立ちます。気温は 10 度だが晴れていて無風で暖かく感じたり、15 度で氷のように風が吹いて寒く感じたりすることがあります。そのため、そこでの reTerminal の目的では、見かけの温度の方がより適切です。
API ドキュメントには、形式と時間別データに関して次のように記載されています。
1 日の現在の時間を取得できる場合は、JSON オブジェクトからそのフィールドを選択して、現在の時間の気温を取得できます。以下は、condensedJSON の出力です:
{
[...]
"hourly_units": {
"apparent_temperature": "degC",
},
"hourly": {
"apparent_temperature": [-1.9, -2.4, -3.2, -3.3, -3.3, [...] ],
}
}
フィールド [hourly][apparant_temperature]
リストです。今日の時間 0 の気温は -1.9
です 摂氏。 1 時間目は -2.4
です など。
私たちの QML ファイルでは、parameters
JSON を含む場合、hour1 にアクセスするための構文は次のようになります:
root.parameters['hourly']['apparent_temperature'][1]
現在の時間を取得する簡単な JavaScript 関数は次のとおりです:
function currentHour() {
const date = new Date()
return date.getHours()
}
2 つを組み合わせると、以下のコードは property
になります。 現在の時間の温度を持っています:
property double currentTemperature: root.parameters['hourly']['apparent_temperature'][currentHour()]
この場合、私は parameters
をチェックしません Text
で後で確認するので、未定義です。 コントロール。それ以外の場合は、999 などのマジックナンバーが表示されます。最も表現力豊かな方法ではありません。
上記の例でも示されているように、API はデータの単位も公開します。他のアイテムにアクセスできるようにアクセスできます:
property string currentTemperatureUnit: root.parameters ? root.parameters['hourly_units']['apparent_temperature'] : ""
上記のプロパティを Text
に組み合わせる コントロール:
Text {
id: currentTemperatureText
text: root.parameters ? currentTemperature + "<small> "
+ currentTemperatureUnit + "</small>" : "..."
anchors.bottom: temperatureIcon.bottom
anchors.left: temperatureIcon.right
anchors.right: parent.right
anchors.leftMargin: 20
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignBottom
font.pixelSize: 54
minimumPixelSize: 45
textFormat: Text.RichText
}
1 つの新しいプロパティは textFormat
です .これを Text.RichText
に設定すると HTML を使用できます。 Text.StyledText
も使用できます <small>
は含まれませんが、いくつかの基本的な HTML には 鬼ごっこ。単位が数字よりも小さいときの見た目が好きです。
更新をクリックしていない場合の完成したコントロールは次のようになります:
JSON を更新すると、次のようになります。
WeatherPage.qml
にコントロールを追加 ファイル、WeatherCode {}
のすぐ下 :
Temperature {
id: temperature
anchors.top: weatherCode.bottom
anchors.topMargin: 30
anchors.left: parent.left
anchors.right: parent.right
parameters: root.parameters
}
以前と同じですが、このコントロールは weatherCode
に固定されています 少し余裕のある底。
パート 1 の仕上げ
基本はすべて揃っています。JSON を解析し、独自のカスタム コントロールでデータを表示しています。素晴らしい!パート 1 を終了するために、さらに 2 つのボタンを追加しましょう。 1 つはアプリを終了するためのもので、もう 1 つは JSON の例をロードするためのものです。終了ボタンは systemd
経由でアプリを再起動します
例のボタンは、私が便利だと思うものです。 JSON データ文字列全体を exampleJson
という名前の文字列プロパティに入れました :
property string exampleJson: '{"generationtime_ms":2.30...
ボタンには、このメソッドが onClicked
としてあります プロパティ:
root.parameters = JSON.parse(exampleJson)
これにより、テスト中のネットワーク呼び出しが節約され、毎回同じデータが得られます。さらに、API のオーバーロードを節約できます。
ここに 2 つのボタンがあります:
Button {
id: exampleButton
anchors.bottom: parent.bottom
anchors.left: refreshButton.right
anchors.margins: 5
text: "Example JSON"
font.pixelSize: 30
onClicked: root.parameters = JSON.parse(exampleJson)
}
Button {
id: quitButtom
anchors.bottom: parent.bottom
anchors.left: exampleButton.right
anchors.margins: 5
text: "Quit"
font.pixelSize: 30
onClicked: Qt.callLater(Qt.quit)
}
最終的な結果は次のようになります:
あなたは素晴らしい仕事をしたので、背中を軽くたたいてください。次のパートでは、風速と風向 (自転車で便利)、永続的な設定、今後数時間の天気、Qt VirtualKeyboard を追加します。
テーブルには、より高度なアンカーと Layout
が含まれます 、Qt VirtualKeyboard には、reTerminal がモジュールをビルドすることを確認するための Yocto 構成も含まれています。