tkinterでシンプルなノートアプリ(メモ帳)を書いてみた
年末辺りから集中的にtkinterを使ってデスクトップアプリを作成していた。
tkinterについて触るのは初めてだったので色々と学びつつアプリ作成をしていたが、せっかく学んだのだから何かしら公開できるシンプルなアプリを書いてみようと思い、余暇に趣味感覚でノートアプリを書いた。
目次
長くなるので目次をおいておく
環境や利用しているライブラリなど
なるべく外部ライブラリは利用しないで作成しようと決めていたので、利用した外部ライブラリ(pip install
するやつ) は実行ファイル化するために使用したcx_Freeze
だけのような気がする。
一応開発時の環境などの下記に箇条書きで残しておくと、
- Python 3.10.1 (pyenvで構築)
- tkinter.TkVersionは
8.6
- 私の開発マシンはM1 MacBook Airだが、そのままではcx_Freezeが動かないので、cx_Freezeを動かすときのみ、
miniforge3-4.10.3-10
をpyenv
を使って切り替えている。
tkinterについてだが、pyenv経由でのPythonインストールやmacOS 10.6以降のユーザでMac版Pythonインストーラを使っている場合、日本語が入力できないケースがある。tkinterが依存しているTcl/Tkパッケージのバージョン 8.5
で起きるもので、こちらの内容については下記のzennの記事に対応策を書いている。
またM1環境でcx_Freezeを利用するためのアレコレについては下記にまとめた。
その他、tkinterについて触りはじめの頃に基本的なアレコレを下記のポストにまとめているので、こちらも併せてはらせていただく。
実装について
実装については直接ソースコードを見ていただくのが早いとは思うが、一応自身の備忘録的な意味でも実装時に記憶に残ったところを書き残しておこうと思う。
(といってもすでに結構忘れてきてしまっているので、自身でもソースコードを見返しながら備忘録として残しておきたいところを抜粋している形だ。)
設計について
このようなGUIアプリを普段書く機会はほとんどなく、設計をどうするかちょっと考えた。
(といっても趣味アプリなので正直そこまで真剣には悩んでいない)
ノートアプリのデータはSQLiteに保存するような作りとなっているので、DBとのやり取りを担当するmodelと表示に関するviewという2つのディレクトリを作成して、それぞれに処理を書くようにした。
本当はMVCのような形でアプリの処理を制御するようなcontrollerも作成しようと思ったのだが、それらの処理は結局 main.py
の中にまとまっている。分離させようと思ったときもあったが、自身のPython力が足りず、そのままとなった形だ。
アプリの実行は main.py
からスタートし、DBとUIの初期化を行う。
UIの処理について
view
ディレクトリでUIを担当すると書いたが、基本的にview
側は
- 与えられたデータの表示(と書いたが、描画制御などについては
main.py
側で書いているな...) - UIに対して実行されたアクションに対する処理の実行
の2つだけを実装している。
UIの配置について
UIの配置についてだが、今回のアプリでは ttk.Labelframe
を作成し、その中に各種コンポーネント(という言い方が正しいのかはわからない)を格納していくようにした。
配置する際、細かな調整は不要だったのでpack
を利用してtkinter側でよしなに配置してもらうようにしている。
tkinter上で実装したイベントハンドラ(command)
おそらくこれはよく利用される形かと思うが、下記はUpdate
ボタンの記述となる。
self.update_button = tk.Button(self.menu_frame, text="Update", command=lambda: self.on_click_update_button(save_note_with_title))
このボタンが押された場合、commad
内に記載された関数や引数を利用して処理を行っている。
仮に引数を渡さない場合、 command=関数名
だけでも良いのだが、引数を渡したい場合 command=lambda: self.on_click_update_button(save_note_with_title)
というようにlambda:
をつけてその後の処理を実装していく必要がある。
Listboxのクリックを取得する処理について(curselection)
今回のアプリでは画面左側にListboxを利用して、ノートの一覧を表示させるようにしている。
この一覧をクリックした際の取得処理には curselection
を利用している。
この curselection
を利用すると、クリックした一覧の位置を取得できる。
これを利用して下記のように取得した一覧項目の値を取得する処理を書いた。
def on_click_note_list(self, event): if self.note_list.curselection(): self.note_list.select_note(self.note_list.get(self.note_list.curselection())
※ 最後に渡しているselect_note
は指定されたノートタイトルをもとに、DBから対象となるノート情報を取得する処理となる。
現在選択中のListboxの値を取得する方法(tk.ACTIVE)
次はListbox
で現在選択されている項目を取得する方法についてだが、これは今回のアプリでは self.note_list.get(tk.ACTIVE)
とやることで取得できる。
Listbox
で持っている get
メソッドに tk.ACTIVE(中身は active という文字列)
を渡すことで現在選択されている値を取得することができる。
def on_click_update_button(self, update_note_with_title): update_note_with_title(self.note_list.get(tk.ACTIVE))
※ update_note_with_title
というのはノートタイトルをもとに対象となるノート情報を更新する処理となる。
一旦ここで休憩
ここまで書いてスタミナが尽きたので、続きはまた後日追記していきます。