目次:
まえがき
できればパスワードマネージャを作りたいわけだが、一通り調べた結果かなり時間がかかることがわかった。そこで当初の設計から大きく変わってしまうが、次の2点だけに絞ってやっていこうと思う。
- Python3とPySide2とQMLを使うGUIにする。
- パスワード生成機能にする。
変わりすぎだろというご批判もおありかと思うが、それよりも私の潔さを褒めていただきたい。 まぁそんなわけでやっていく。バージョン0.1としてはこれくらいで良いことにして、いつか時間があったら機能を追加していく。
変更履歴
新規作成:2020/03/07
この記事の開発環境
- バージョン: Python 3.8.1
- IDE: Spacemacs & QtCreator
- ライブラリ: PySide2 (5.14.1)、Qt5(Desktop Qt 5.12.7 clang 64bit)、Qt Quick/QML
- 環境構築: pyenv、pyenv-virtualenv
- OS: macOS
PySide2による開発に必要なもの
- Python 3.5以降
- Qt5
- PySide2
- Qt creator
- Spacemacs (推奨)
Qtの公式サイトから「open source」のQt creatorをダウンロードする。 インストール時にQt5とQtの各種キットがインストールされる。 インストール出来る物がたくさん有るので、よく選んだ方がよい。全部だと数十ギガある。
ロジック部分とGUIのデザイン部分を分離する
基本的に制作は自分の使いやすいIDEなりエディタなりでやれば良いが、QMLについてはQt Creatorがドラッグ&ドロップで作れるのでGUIのデザイン部分のためだけにQt Creatorを使うことにする。
- ロジック部分は.pyへ記述していく。
- GUIのデザイン部分は.qmlへ記述していく。
簡単に言えば上記のようにやっていく。あとはロジックとデザインを結びつけるようにすれば良い。
QtQuick/QMLでGUIをデザインする
Qt Creatorで制作していく。新しいプロジェクトを作成する時に、テンプレートの選択画面で「他のプロジェクト」→「Qt Quick UI Prototype」を選択する。そうして出来上がるのが、QMLファイルになる。
Qt Creatorの「デザイン」の機能はこのQMLファイルを開いていないと使えない。作成されると最低限必要なものがimportされた状態になる。
ロジック側の初期状態
先にロジック部分を載せておく。このファイルは自分で作成する。
import sys import os from PySide2.QtCore import QUrl from PySide2 import QtCore, QtWidgets, QtQml class Connect(QtCore.QObject): def __init__(self, parent=None): super(Connect, self).__init__(parent) @QtCore.Slot() def button_clicked(self): print("button clicked") if __name__ == '__main__': os.environ["QT_QUICK_CONTROLS_STYLE"] = "Material" app = QtWidgets.QApplication(sys.argv) myconnect = Connect() engine = QtQml.QQmlApplicationEngine() ctx = engine.rootContext() ctx.setContextProperty("Connect", myconnect) engine.load(QUrl("pw-manager.qml")) if not engine.rootObjects(): sys.exit(-1) sys.exit(app.exec_())
参考サイト1:がれすたさんのDI Y日記:PySide2でQtQuick(qml)使うメモ1
参考サイト2:Qt.io:Qt for Python Documentation
QMLファイルの初期状態
import QtQuick 2.12 import QtQuick.Window 2.12 Window { visible: true width: 640 height: 480 title: qsTr("Hello World") }
CSSのようなJsonのような記法であることがわかる。分かりやすい。
Qt for Python(PySide2)のモジュール
パスワードマネージャを制作するにあたって必要な最低限のモジュールになると思われる。当然モジュールはここに挙げるよりもずっと多い。バージョン1.0としては最小限の機能の実装としたいので、むしろ引き算の目で選びたい。
基本モジュール
Qt Core
シグナルとスロット、プロパティ、アイテムモデルの基本クラス、シリアル化など、GUI以外のコア機能を提供する。
Qt GUI
QtCoreをGUI機能で拡張:イベント、ウィンドウとスクリーン、OpenGLとラスターベースの2Dペイント、画像を扱う。
Qt Widgets
UIのグラフィカル要素を含む、すぐに使用できるウィジェットをアプリケーションに提供します。
QMLとQt Quick
Qt QML
モジュールとやり取りするためのベースPython API。
Qt Quick
QtアプリケーションにQt Quickを埋め込むためのクラスを提供します。
Qt QuickWidgets
Qt Quickをウィジェットベースのアプリケーションに埋め込むためのQQuickWidgetクラスを提供します。
QMLのパーツを配置する
必須のパーツは、
- 決定(実行する)ボタン 1個
- 条件を選べるようにするチェックボックスが 6個
- 結果を表示する、表示領域 1個
想像以上に時間がかかった。。。これは全くの見た目だけ。
QMLのソースコード
import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Controls 2.3 import QtQuick.Controls.Material 2.0 Window { visible: true width: 640 height: 480 title: qsTr("文字列ジェネレータ") color: "darkgrey" Button { id: button x: 113 y: 35 text: qsTr("生成") } Button { id: button1 x: 450 y: 35 text: qsTr("クリア") } GroupBox { id: groupBox1 x: 70 y: 104 width: 500 height: 64 title: qsTr("文字数指定") Row{ width: 476 height: 40 anchors.centerIn: parent spacing: 70 RadioButton { id: radioButton x: 9 y: 3 text: qsTr("8文字") checked: true } RadioButton { id: radioButton1 x: 162 y: 3 text: qsTr("16文字") } RadioButton { id: radioButton2 x: 334 y: 3 text: qsTr("24文字") } } } GroupBox { id: groupBox x: 70 y: 186 width: 500 height: 100 title: qsTr("条件指定") Row{ width: 476 height: 40 anchors.verticalCenterOffset: -15 anchors.horizontalCenterOffset: 0 anchors.centerIn: parent spacing: 70 CheckBox { id: checkBox x: 0 y: 0 text: qsTr("大文字") } CheckBox { id: checkBox1 x: 369 y: 0 text: qsTr("記号") } CheckBox { id: checkBox3 x: 189 y: 0 text: qsTr("数字") } } Row{ width: 476 height: 40 anchors.verticalCenterOffset: 21 anchors.horizontalCenterOffset: 0 anchors.centerIn: parent spacing: 50 RadioButton { id: radioButton3 x: 189 y: 0 text: qsTr("文字始まり") checked: true } RadioButton { id: radioButton4 x: 369 y: 0 text: qsTr("記号始まり") } RadioButton { id: radioButton5 x: 0 y: 0 text: qsTr("数字始まり") } } } GroupBox { id: groupBox3 x: 70 y: 302 width: 500 height: 57 title: qsTr("形式指定") Row{ width: 476 height: 40 anchors.centerIn: parent spacing: 70 RadioButton { id: radioButton6 x: 0 y: 5 text: qsTr("なし") checked: true } RadioButton { id: radioButton7 x: 192 y: 5 text: qsTr("ー形式") } RadioButton { id: radioButton8 x: 373 y: 5 text: qsTr(".形式") } } } GroupBox { id: groupBox2 x: 70 y: 373 width: 500 height: 88 title: qsTr("出力文字") Text { id: element x: 0 y: 15 width: 476 height: 36 text: qsTr("") font.pixelSize: 12 } } }
指定できるのは大きさや位置、色などだが、これらは細かく指定できるし、指定の仕方もいくつかある。ドラッグ&ドロップで微調整はできるが、ある程度詳しく調べてxとyだけでなくしっかりとレイアウトできる属性を指定した方が良い。
RowやGroupBoxなどのパーツを纏めてくれるものを使った方がきれいに並べられる。纏められたものは親と子の関係が出来上がるらしく、親を基準に並べたりできるので本格的にやるならそこまでやった方がいいと思う。
むすび
とりあえずGUI部分はこんな感じでよしとする。次はロジックの部分を作ってこのGUIとつなげていこう。
コメント