Pythonの GUI ツール Tkinter
Tkinter に於いて、geometry では、ウィンドウのサイズをピクセル単位でサイズを指定するのに、Button は文字数で指定するという、直接的にピクセルで指定する方法がないということに憤りを感じました。
そこで、以下のようなものを作ってみました。
example.py
import tkinter as TK
class X:
def __init__(self):
self._app = TK.Tk()
self._pv = TK.PhotoImage(width=1, height=1)
self._bwfx, self._bhfx, self._bwmin, self._bhmin = None, None, None, None
def _ent(self, func, *args, **kargs):
ret = None
if callable(func):
self._app.update()
ret = func(*args,**kargs)
self._app.update()
return ret
def protoType1(self):
self._app.geometry("200x200")
w_width = self._ent(self._app.winfo_width)
btn1 = self.newBtn(0, 0)
btn2 = self.newBtn(0, 1)
self.setSize(btn1, w_width, 20)
self.setSize(btn2, w_width, 20)
self._app.mainloop()
def newBtn(self, column, row):
widget = self._ent(TK.Button, self._app, image=self._pv)
self._ent(widget.grid, column=column, row=row)
if self._bwfx is None:
self.sizeOne(widget)
return widget
def setSize(self, widget, width, height):
_width = round(width / self._bwfx) - self._bwmin
_height = round(height / self._bhfx) - self._bhmin
self._ent(widget.configure, width=_width, height=_height)
# Find the size per width|height
def sizeOne(self, btn):
# The minimum width of the button per button requested width 0.
self._ent(btn.configure, width=0, height=0)
self._bwmin = self._ent(btn.winfo_width)
self._bhmin = self._ent(btn.winfo_height)
# Button width per button requested width 5.
self._ent(btn.configure, width=5, height=5)
b5w = self._ent(btn.winfo_width)
b5h = self._ent(btn.winfo_height)
# Calculating size per unit of width
self._bwfx = round((b5w - self._bwmin) / 5)
self._bhfx = round((b5h - self._bhmin) / 5)
if __name__ == '__main__':
x = X()
x.protoType1()
※ このコードは、RaspberryPi5 と WSL(Ubuntu) の python で動作を確認しています。
解説
要素 or メソッド | 説明 |
---|---|
_pv | ボタンの image オプションに設定される 1x1 ピクセルの透明な PhotoImage で、これによりボタンの width と height がピクセル単位で扱われるようにします。 |
_ent | 関数呼び出しの前後に self._app.update() を実行することで、GUI の状態を強制的に更新します。 |
protoType1 | サンプルとして、ウィンドウを作成し、2つのボタンを配置し、ウィンドウの初期幅に合わせてボタンの幅を設定します。 |
newBtn | ボタンを作成し、最初に sizeOne メソッドを呼び出して基準となるピクセル単位の幅と高さを取得します。 ボタンを作成したら、まず grid で配置することで、その後に呼ばれる sizeOne に於いて幅やサイズが取れるようになります。 |
setSize | 指定されたピクセル単位の幅と高さに基づいて、ボタンの width と height を計算しています。 self._bwfx と self._bhfx は 1 ピクセルあたりの文字幅・高さの係数を表します。 |
sizeOne | ボタンの width を 0 と 5 に設定したときの実際のピクセル幅の変化を計測し、1 文字あたりのピクセル幅と高さを計算します ボタンの width が 0 のときは、_bwmin と _bhmin が、文字が含まれていない場合の、ボタン自体のサイズとなります。 ここで重要なのが、app.update() です。スクリプトでは、grid() の直後に、winfo_width() を行うと、文字数が返ってきます。しかし、python のインタプリタから手入力で確認する場合には、winfo_width() はピクセル数を返すので、app.update() によってイベントを処理させることでピクセル数が取れるようにしています。 |
本節のまとめ
今回は、ボタンを例に作成しました。
他のウィジェットでは、周囲のパディングやエッジのサイズが異なるかもしれないので、ウィジェットの種類ごとに行うと良いかもしれません。これらの処理をコンポーネント、もしくはアサインツールとして利用できれば、ピクセル単位でGUI要素を配置する際に利用できるのでは、と思います。