Learning)の流行とともにPythonの人気が上がっていますね。Pythonで画像を表示・描き込み・保存するGUIアプリケーションを以前から作っていたもコードなどを整理して作ってみました。自分の理解を整理するためにも、その仕組みを書いてみます。Python(PySide2)というライブラリです。Linuxなどの様々なOSで動作するクロスプラットフォームなアプリケーションが開発できます。Pythonを使いました。GUIアプリケーション作りではオブジェクト指向について把握していると理解しやすいです。画像を描画するときにいくつもオブジェクトが出てきて、それぞれの役割や関係がわかりづらいところが初心者に辛く感じるところですが、きれいな形でなくても動くものができてくると理解が進みます。(経験談)なので、作りたいイメージがあったら諦めずに色々試行錯誤してみてください。この記事がそのときの一助にでもなれば幸いです。アプリの全体像アプリの全体像は下図のようになります。Layoutというウィンドウなどのサイズに合わせて自動的に置いた部品(Widget)を整列する機能を持つもので画面構成を管理しています。QVBoxLayout()が縦方向に整列させ、QHBoxLayout()が横方向に整列させます。その他に名称とその値のような組にしたいときにQFormLayout()を使います。使用例は以下のようになります。MainWindow(QMainWIndow)を作ります。この中に様々な機能を持たせた部品(Widget)を配置し、それを押したときなどの動作を記述していきます。QWidget(self)のように宣言しておかないとLayoutを設定していけませんでした。アプリケーションの起動のためのコードは、以下のようになります。)のなかで宣言します。メニューバーを作り、その中に「File」というメニューを作成するには下のようにします。Open」という項目を作りたい場合は下のようにします。Image'としています。2行目でCtrl+Oのショートカットキーでこの項目を選択できるように設定しています。3行目はこの項目が選択されたときの動作を設定する関数とつなげています。ここは次の節で説明します。4行目でこの項目をfile_menuに登録しています。部品へのアクションを受け取る仕組みQtではユーザーからの操作と対応するコンピュータのリアクションをSignalとSlotという仕組みで実施しています。ユーザーがメニューのボタン、マウスをドラッグするなどの操作をするとSignalを発します。各シグナルを受け取るように定義したSlotで対応する処理を実行します。具体的には、メニューバーの項目を選択したときの動作は下のように書きます。triggeredシグナルを発信する。そのシグナルはopen_org_img_dialog関数に接続される。self.org_img_path_label.setText(self.org_img_file_path)後で説明するカラーバーからマウスクリックで色を選択したとき、その選択色を表示用の描画領域に四角形で描画して、ユーザーにわかりやすく表示しようとします。このとき、カラーバーと選択色描画領域のオブジェクト間で作用する必要が出てきます。そのとき親となるメインウィンドウを介してSignalとSlotをつなげる必要が出てきます。その場合に選択色描画領域に載せる描画アイテムを管理するクラスで独自のSignalを定義し、クリックしたところのカラー情報を持つSignalを発信(emit)するようにしています。具体的には、下のようなコードになります。self.color_bar_scene.img_info.connect(self.set_selected_color)画像表示の仕組み画像表示にはいくつかのWidgetを連携させます。下図のような関係になっており、MainWindowに描画領域オブジェクトであるQGraphicsViewを用意し、その中に描画オブジェクトを保持・管理するQGraphicsSceneを配置し、QGraphicsSceneにラインや円などの描画や画像を加えていきます。メインの描画領域に設定するQGraphicsSceneにはカーソルのツールを選んでいるときは表示されている画像の画素情報をステータスバーに表示し、ペンや消しゴムのツールを選んでいるときは画像の上のレイヤーにお絵描きをするようにします。そのような自分で設定した機能を追加するためQGraphicSceneを継承したGraphicsSceneを以下のように作成します。初期化init関数において、親である描画領域のQGraphicsViewとそのさらに親であるMainWindowを設定することで、このGraphicsSceneの各アイテムで得た情報を描画領域やウィンドウに渡せるようにします。最初はQGraphicsViewとQGraphicsSceneがよく分からないけど分かれていてなんか複雑でコンテンツへのアクセスや制御が面倒!と思いました。これは描画する対象コンテンツは変わらなくても、視点を変えて見える範囲(描画できる範囲)で描画するという複雑な要求にも応えられる設計にしているためと思われます。描画するコンテンツが描画エリアより大きいときにスクロールバーで視点を変えながら表示する、3Dオブジェクトを視点を変えながら表示するといったことが考えられます。self.window.statusBar().showMessage(message)QGraphicsViewのドキュメントへのリンクQGraphicsSceneのドキュメントへのリンク画像オブジェクトQGraphicsSceneに画像を配置するには、QPixmapという形式にして、QGraphicsScene.addItem(QPixmap)とします。QPixmap形式だと各画素の情報を取得したり、書き換えたりすることができないため、QImage形式で保持しておいて、それをQPixmapに変換して描画させます。画像ファイルからQImageを作成し、それをQPixmapにして、QGraphicsSceneに加えるには以下のようなコードとなります。QPixmap.fromImage(self.org_qimg)scene.addItem(self.org_pixmap)空の各8bit(256階調)RGBA(Aは透過度)のQImageを作るには、以下のようなコードとなります。QImage.Format_RGBA8888)QImageのドキュメントへのリンクQPixmapのドキュメントへのリンクカラーバーの設定こちらの記事を参考にさせていただき、ペンの色を選択するカラーバーをヒートマップ調(低温の青色から高温の赤色まで滑らかに変化)で作ってみました。カラーバーをセットするオブジェクトは「部品へのアクションを受け取る仕組み」の説明で一部記載しましたがQGraphicsSceneを継承したGraphicsSceneForToolsというクラスを作り、それを使っています。それによりその上でマウスクリックなどすることで、そのオブジェクトから押された位置に応じたSignalを発するようにし、そのオブジェクトを配置した親オブジェクトのMainWindow(正確にはMainWindow->QGraphicsView->GraphicsSceneForTools)でSignalに受け取るSlot関数を用意することで、ユーザーがカラーバーから選んだ色で選択色表示領域を塗りつぶして、わかりやすく表示します。event)のおいてマウスクリックをされたときにセットされている描画アイテム(ここではカラーバー)のクリックされた座標位置の色(self.pix_rgb)を持たせたSignal信号をself.img_info.emit(self.pix_rgb)として出すようにしています。MainWindow側では、self.color_bar_scene.img_info.connect(self.set_selected_color)として、GraphicsSceneForToolsオブジェクトが該当するSignalを発したとき、受け取り側のSlot関数としてset_selected_color()を用意します。具体的には以下のようなコードになります。カラーバーをセットする。カラーバーの元となる色変化データはself.colormap_dataに入っている。作成方法はソースコードもしくは参考記事を参照してください。DesignerというGUI画面上でボタンなどのパーツを配置するツールも付いています。慣れないうちはどんなWidgetがあるかなどイメージしやすいため、これを使って外観を作ってみてるととわかりやすいかもしれません。ソースコード作成したアプリのソースコードを以下の場所に掲載します。upLoginユーザーは見つかりませんでした。