はじめに
この記事は Qt Advent Calendar 2024 6日目の記事です。
昨日は一個空いていますね。Qt が好きな人がいましたら埋めていただければと思います。
また、この記事は Slint Advent Calendar 2024 6日目の記事でもあります。
昨日は @hermit4 さんの Slint言語入門(2) でした。
.slint は元々 QtQuick や Qt for MCU を開発していた開発者が設計/開発をしているだけあって、QML よりもいいところがたくさんありますね。
今日は、PSD を読み込んで Qt で表示するモジュール(ライブラリやそれを利用したサンプル、テスト)を開発したので、それを紹介します。
QtPsd モジュール
モチベーション
2010頃からなにかの UI を実装することが増えてきて、デザインは PSD ファイルでもらうことが多かったという記憶があります。(当時はまだ Figma とかはなく、Sketch が使われはじめたくらいだった気がします。)
その頃から、このデザインを自動で QML に変換できないかなと思って、ことあるごとに PSD の仕様 を眺めていました。
その後、Qt Design Studio が Photoshop のプラグイン を提供し、Photoshop から QML への変換が可能になりました。
が、しかし、上記のワークフローは基本的にデザイナーさんが担当するもので、プログラマーの私は「これじゃないな」と感じていました。
PSD ファイルをもらったプログラマーが、自分の思った感じの QML を出力できるといいなと思い、PSD をロードできるペイントソフト Krita の QML のエクスポートまわりのコード を自分用に魔改造したこともありました。
それも物足りなかったので、もう少しちゃんと PSD を解析して、もう少しちゃんと QML を生成できるようにしたいと思っていました。
先月末にパシフィコ横浜で開催された EdgeTech+ 2024 に会社として出展することにして、そのためにデモ機をいくつか準備する必要があったので、この期を逃すわけにはいくまいと開発をしたのが、以下で公開をしている Qt 向けの PSD モジュールになります。
できること
- PSD ファイルを解析して、レイヤー構造とレイヤーの様々な情報を Qt で扱いやすい形で提供します
- プレビュー用のサンプルアプリがあります
- QtQuick の形式でエクスポートができます
上記の PSD は Qt Design Studio のチュートリアルかウェビナー向けに公開 されているものです。
Qt Quick にエクスポートすると以下のようになります。
この PSD の場合、オリジナルの再現度はそこまで高くはありません。
EdgeTech+ 向けのデモを作りました
コインパーキングの精算機の UI
コインパーキングUI.psd を Qt Quick のコード に変換し、雑に ロジックを記載した以下の qml を追加しました。
import QtQuick
import "ui"
Window {
id: root
width: ui.width
height: ui.height
visible: true
title: currentPage
property int currentPage: 0
MainWindow {
id: ui
welcome.visible: root.currentPage === 0
welcome.onClicked: root.currentPage++
header.visible: root.currentPage > 0
cancel.onClicked: root.currentPage = 0
footer.visible: root.currentPage > 0
parkingSlot.visible: root.currentPage === 1
parkingSlot.onVisibleChanged: {
digit1.text = ''
digit10.text = ''
}
accept.onClicked: root.currentPage++
key0.onClicked: keyClicked('0')
key1.onClicked: keyClicked('1')
key2.onClicked: keyClicked('2')
key3.onClicked: keyClicked('3')
key4.onClicked: keyClicked('4')
key5.onClicked: keyClicked('5')
key6.onClicked: keyClicked('6')
key7.onClicked: keyClicked('7')
key8.onClicked: keyClicked('8')
key9.onClicked: keyClicked('9')
keyC.onClicked: {
digit1.text = ''
digit10.text = ''
}
function keyClicked(key) {
if (digit1.text === '') {
digit1.text = key
} else if (digit10.text === '') {
digit10.text = digit1.text
digit1.text = key
}
}
payment.visible: root.currentPage === 2
cash.onClicked: root.currentPage++
card.onClicked: root.currentPage++
ic.onClicked: root.currentPage++
pay.onClicked: root.currentPage++
goodBye.visible: root.currentPage === 3
goodBye.onClicked: root.currentPage = 0
Timer {
repeat: false
running: ui.goodBye.visible
interval: 3000
onTriggered: root.currentPage = 0
}
}
}
元の PSD を完全に再現はできていないのですが、デモとしては十分な出来です。
標準的な Qt 以外の対応
同じデザイン(PSD)から、色々なフレームワークで UI を作ることにもチャレンジした結果、以下のバリエーションのサンプルアプリを生成することができました。
QtQuick(GPU なしでも動く版)
Toradex Verdin AM62 Solo で meta-qt6 を動かしてみた の環境で動かすと以下のようになります。
Slint
.slint 形式でもエクスポートできるように対応しました。
任意の解像度に拡大縮小をしてエクスポートができるようにもしたので、pico や pico2 で動く Slint のアプリケーションも作成しました。
Flutter(Experimental)
Flutter の対応も進めているところです。
投票所の投票端末のデモ
ちょうど準備期間に選挙があったのと、投票所で文字を書くのが面倒くさかったので、
タッチで投票できる感じのデモを作ってみました。
PSD はこれ で、Slint 向けにエクスポートしたものが、以下のものです。
先日の Raspberry Pi 5 で slint を動かす で動かした UI は、実はこうやって作ったので、ソースコードが手書きに比べて構造化されていない状態でした。
現在のステータス
とりあえず公開はしましたが、まだまだアルファ版という感じで未対応の部分やバグがたくさんあります。
大きく分けて、以下の点をこれから改善していきたいです。
様々な PSD を正しく扱えるようにする
のサンプルPSDをすべてちゃんとパースできるようにしたいです。
Qt の API を改善する
とりあえず動いているけれど、理想の設計や実装からはかけ離れているところが多いので、これから改善していきたいです。
エクスポートできるフレームワークの種類を増やす
- Qt Widgets
- その他の宣言型 UI フレームワーク
サンプルアプリを増やす
- Qt Creator のプラグイン?
- QImageIOPlugin
- QQuickImageProvider
謝辞
このプロジェクトの開発にあたり、フリーランスの日高隆博さんにたくさん協力をしていただきました。
この場を借りて御礼を伝えたいと思います。
おわりに
今回は PSD ファイルをロードしてパースする Qt 向けのモジュールの紹介でした。
Qt や PSD や、アプリケーション開発のワークフローに興味がある方がいましたら、是非開発に参加して、より効率よく GUI の開発ができるような未来を作りましょう。
明日は、Slint の方は @hermit4 さんが何かを書いてくれるようです。
Qt の方は未定ですね。
お楽しみに!