見出し画像

【PythonでGUIを作りたい】Tkinterで作る画像編集ソフト#2:仕様検討と簡易テスト

こんにちは。すうちです。

昨日、今日と各地で真夏日が続いていますが、皆さんいかがお過ごしでしょうか?

土日に私は、ほぼ自宅にこもっていたので大丈夫でしたが、最近気温差が激しいので体調管理に気を付けたいと思います。

本題です。先週から新しい試みで連載形式の記事を投稿しています。

前回の記事はこちらです。

今回は先週の続きでTkinterを使ったGUI(画像編集ソフト)構築を目標に仕様検討に関わる話を書きたいと思います。


◆はじめに

GUIソフトのイメージ(作りたいもの)

前回のメモです。

・ユーザ操作はGUI(今回はTkinter)
・画像の簡単な加工(クリップ、回転等)
・動画の簡単な編集(画像加工も可)
・動画や画像ファイルの読み書き可

できるだけPythonの簡単なプログラムやTkinterの基本機能の範囲で実現することが目標です。

メモを元に、まずはユーザ視点からGUIで必要な部品やレイアウトを考えていきたいと思います。


◆GUIの仕様検討

GUIの外観

いきなりですが、GUIレイアウトの完成イメージです。

GUIレイアウトの完成イメージ(仮)

入力選択(Set Folder)

対象ファイルのフォルダ選択です。
フォルダ配下にあるファイル(jpg、pngなど)を切替可とします。

編集機能(回転、反転)

回転(Rotate)反転(Flip)のメニューです。回転は0/90/180/270度。反転は上(U)/下(D)左(L)/右(R)を用意。ラジオボタンでどれか一つを選択可。回転・反転の実行は各ラジオボタン選択時と考えます。

編集機能(クリップ)

クリップはTryボタン押下で有効。Doneボタンでクリップ完了。クリップ領域の選択はマウス操作で矩形範囲を指定する予定です。

編集決定(Save)

編集した画像を保存するボタンです。日時ファイル名で保存します。

編集取消(Undo)

編集前のオリジナル画像に戻すボタンです(編集状態を時系列で戻すUndoは未サポート)。

表示切替(Prev/Next)

編集対象のファイルを切替えるボタンです。

◆GUI画面のウィンドウ構成

メインウィンドウ(GUI画面のベース)
GUIを構成するTkinterのメインウィンドウです。このウィンドウにいくつかのサブウィンドウを配置して領域を分割します。
※前回メインフレームと記載した部分です。今後画像のフレームと区別するため「ウィンドウ」という表現に統一します。

サブウィンドウ1(フォルダの設定)
フォルダの設定を配置するウィンドウ(右側上)です。

サブウィンドウ2(編集の設定)
画像編集の設定を配置するウィンドウ(右側中央)です。

サブウィンドウ3(切替ボタンの配置)
編集画像の切替ボタンを配置するウィンドウ(左下)です。

キャンバスウィンドウ(編集画像の表示)
編集画像を表示するウィンドウ(左側)です。

ウィンドウ部分のコードは、以下の様な感じです。

    # メインウィンドウ
    window_root = tk.Tk()
    # メインウィンドウサイズ指定
    window_root.geometry("800x600")
    # メインウィンドウタイトル
    window_root.title('GUI Image Viewer v0.10')
    
    # サブウィンドウ
    window_sub_ctrl1 = tk.Frame(window_root, height=200, width=300)
    window_sub_ctrl2 = tk.Frame(window_root, height=600, width=300)
    window_sub_ctrl3 = tk.Frame(window_root, height=150, width=400)
    window_sub_canvas = tk.Canvas(window_root, height=450, width=400, bg='gray')


◆GUI部品の簡易テスト

今回は生成したGUI部品の操作をイベント関数のログで確認しました。

各部品の生成時に指定するcommandの引数は、ボタンやラジオボタン操作時に実行されるイベント(関数)です。

GUI部品の生成コード

    # フォルダ選択ボタン生成
    button_setdir = tk.Button(window_sub_ctrl1, text = 'Set Folder', width=10, command=event_set_folder) 
    # テキストエントリ生成
    entry_dir = tk.Entry(window_sub_ctrl1, text = 'entry_dir', textvariable=str_dir, width=40)
    
    # 切替ボタン生成
    button_next = tk.Button(window_sub_ctrl3, text = '>>Next', width=10, command=event_next)
    button_prev = tk.Button(window_sub_ctrl3, text = 'Prev<<', width=10, command=event_prev)
    
    # クリップボタン生成
    button_clip_start = tk.Button(window_sub_ctrl2, text = 'Try', width=5, command=event_clip_try)
    button_clip_done = tk.Button(window_sub_ctrl2, text = 'Done', width=5, command=event_clip_done)
    
    # Save/Undo生成
    button_save = tk.Button(window_sub_ctrl2, text = 'Save', width=5, command=event_save)
    button_undo = tk.Button(window_sub_ctrl2, text = 'Undo', width=5, command=event_undo)
    
    # ラジオボタン生成
    radio_rotate = []
    for val, text in enumerate(['0°','90°','180°','270°']):
        radio_rotate.append(tk.Radiobutton(window_sub_ctrl2, text=text, value=val, variable=radio_intvar1,command=event_rotate))
    radio_intvar1.set(0)
        
    radio_flip = []
    for val, text in enumerate(['U','D','L','R']):
        radio_flip.append(tk.Radiobutton(window_sub_ctrl2, text=text, value=val, variable=radio_intvar2,command=event_flip))
    radio_intvar2.set(0)

イベントの実行関数(簡易テスト用)

sys._getframe().f_code.co_nameは、実行されている関数名を取得するコードです。これによりGUI操作時のログを出しています(この内容であれば直接print文にテキストで書いても同じですね)。

今後は、これらのイベント関数に実際の処理を書いていきます。

def event_set_folder():
    print(sys._getframe().f_code.co_name)
    
def event_prev():
    print(sys._getframe().f_code.co_name)
    
def event_next():
    print(sys._getframe().f_code.co_name)
    
def event_rotate():
    function = sys._getframe().f_code.co_name
    val = radio_intvar1.get()
    print('{} {}'.format(function, val))

def event_flip():
    function = sys._getframe().f_code.co_name
    val = radio_intvar2.get()
    print('{} {}'.format(function, val))
    
def event_clip_try():
    print(sys._getframe().f_code.co_name)
    
def event_clip_done():
    print(sys._getframe().f_code.co_name)
    
def event_save():
    print(sys._getframe().f_code.co_name)
    
def event_undo():
    print(sys._getframe().f_code.co_name)

イベント実行時のログ

上記ログからGUIの操作は機能していることが確認できました。

◆今後の予定

ユーザ仕様:
 GUI実現機能などの仕様検討
内部設計:
 目標仕様の実現に向けた設計検討
実装・コーディング:
 設計方針に基づく実装やコーディング
テスト・デバッグ:
 作成したプログラムの評価
仕様変更・機能追加:
 一旦作成したGUIに機能追加など検討

次回は、GUIの内部設計やイベントの実装について検討予定です。

最後に

今回はここまでです。

実際にユーザ操作の観点で考えると最初に頭で考えた仕様は矛盾が生じたり、使い方が分かりにくい場合もあって予想より検討に時間がかかりました。決まってしまえばGUIの配置自体は単純作業で進みました。

GUI構築の流れを大まかに把握したい方、Tkinterを使うことを検討されている方に、何か参考になれば幸いです。

最後まで読んで頂き、ありがとうございました。


ーーー

ソフトウェアを作る過程を体系的に学びたい方向けの本を書きました(連載記事に大幅に加筆・修正)

Kindle Unlimited 会員の方は無料で読めます。


#連載記事の一覧

ーーー

この記事が気に入ったらサポートをしてみませんか?