0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Tkinterのボタンサイズをピクセル単位で指定できるようにする

Last updated at Posted at 2025-05-14

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()

※ このコードは、RaspberryPi5WSL(Ubuntu)python で動作を確認しています。

解説

要素 or メソッド  説明
_pv ボタンの image オプションに設定される 1x1 ピクセルの透明な PhotoImage で、これによりボタンの widthheight がピクセル単位で扱われるようにします。
_ent 関数呼び出しの前後に self._app.update() を実行することで、GUI の状態を強制的に更新します。
protoType1 サンプルとして、ウィンドウを作成し、2つのボタンを配置し、ウィンドウの初期幅に合わせてボタンの幅を設定します。
newBtn ボタンを作成し、最初に sizeOne メソッドを呼び出して基準となるピクセル単位の幅と高さを取得します。
ボタンを作成したら、まず grid で配置することで、その後に呼ばれる sizeOne に於いて幅やサイズが取れるようになります。
setSize 指定されたピクセル単位の幅と高さに基づいて、ボタンの widthheight を計算しています。
self._bwfxself._bhfx は 1 ピクセルあたりの文字幅・高さの係数を表します。
sizeOne ボタンの width05 に設定したときの実際のピクセル幅の変化を計測し、1 文字あたりのピクセル幅と高さを計算します
ボタンの width0 のときは、_bwmin_bhmin が、文字が含まれていない場合の、ボタン自体のサイズとなります。
ここで重要なのが、app.update() です。スクリプトでは、grid() の直後に、winfo_width() を行うと、文字数が返ってきます。しかし、python のインタプリタから手入力で確認する場合には、winfo_width() はピクセル数を返すので、app.update() によってイベントを処理させることでピクセル数が取れるようにしています。

本節のまとめ

今回は、ボタンを例に作成しました。
他のウィジェットでは、周囲のパディングやエッジのサイズが異なるかもしれないので、ウィジェットの種類ごとに行うと良いかもしれません。これらの処理をコンポーネント、もしくはアサインツールとして利用できれば、ピクセル単位でGUI要素を配置する際に利用できるのでは、と思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?