7
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Tkinter でウィジェットを動的に追加したり削除したりするアレ

Posted at

この記事を書いた理由

ネットを探してもなかなか見つからなかったため。
需要あると思うんですけどね。意外と。

想定読者

エントリー(テキストボックス)ウィジェットを自由に追加したり、削除したりする、スマホとかでよく見るアレがしたいんじゃあ!
入力項目は3つまでとかダサすぎる・・・。
とか考えている人。

Tkinter って何?
という人はちょっと向いていないかもしれません。

いきなりソースコード

コメント増し増しなので頑張って読んでください。
要するに、エントリーウィジェットのインスタンスと並び順を配列と変数で管理して、良い感じに表示してるだけです。
ボタンだと背景が透明にならないのでラベルで代用。

応用すれば、エントリー(テキストボックス)以外のウィジェットでも同じことできますね。

import tkinter as tk

# Tkinter お決まりフレーズ
class App(tk.Tk) :
    def __init__(self) :
        super().__init__()

        # タイトルとウィンドウサイズ
        self.title('appendEntry')
        self.geometry('640x480')

        # エントリーウィジェットをグループ化するためのフレーム
        self.FrameWindow = tk.Frame(self)
        self.FrameWindow.grid(row=0)

        # エントリーウィジェットマネージャを初期化
        self.Entries = []        # エントリーウィジェットのインスタンス
        self.insertEntries = []  # 追加するボタンのようなラベル
        self.removeEntries = []  # 削除するボタンのようなラベル

        # こちらはインデックスマネージャ。ウィジェットの数や並び方を管理
        self.index = 0           # 最新のインデックス番号
        self.indexes = []        # インデックスの並び

        # 最初のエントリーウィジェットを作成して配置
        self.createEntry(0)

        # テキストを取得ボタン作成
        self.GetEntryTextButton = tk.Button(
            text='テキストを取得',
            command=self.GetEntryTextButton_click
        )
        self.GetEntryTextButton.grid(row=1)

    # エントリーウィジェットを追加するボタンのようなラベルをクリック
    def insertEntry_click(self, event, id) :

        # 追加する位置
        next = self.indexes.index(id) + 1
        self.index = self.index + 1

        # エントリーウィジェットを作成して配置
        self.createEntry(next)

    # エントリーウィジェットを削除するボタンのようなラベルをクリック
    def removeEntry_click(self, event, id) :

        # 削除する位置
        current = self.indexes.index(id)

        # エントリーウィジェットと追加・削除ボタンのようなラベルを削除
        self.Entries[current].destroy()
        self.insertEntries[current].destroy()
        self.removeEntries[current].destroy()

        # エントリーウィジェットマネージャから削除
        self.Entries.pop(current)
        self.insertEntries.pop(current)
        self.removeEntries.pop(current)
        self.indexes.pop(current)

        # 再配置
        self.updateEntries()

    # エントリーウィジェットを再配置
    def updateEntries(self) :

        # エントリーウィジェットマネージャを参照して再配置
        for i in range(len(self.indexes)) :
            self.Entries[i].grid(column=0, row=i)
            self.Entries[i].lift()
            self.insertEntries[i].grid(column=1, row=i)
            self.removeEntries[i].grid(column=2, row=i)

        # 1つしかないときは削除ボタンのようなラベルを表示しない
        if len(self.indexes) == 1 :
            self.removeEntries[0].grid_forget()

    # エントリーウィジェットを作成して配置
    def createEntry(self, next) :

        # 最初のエントリーウィジェットを追加
        self.Entries.insert(next, tk.Entry(self.FrameWindow, width=30))

        # エントリーウィジェットを追加するボタンのようなラベルを作成
        self.insertEntries.insert(next, tk.Label(
            self.FrameWindow,
            text='+',
            fg='#33ff33',
            font=('Arial Black', 20)
        ))

        # エントリーウィジェットを削除するボタンのようなラベルを作成(初期の段階では表示しない)
        self.removeEntries.insert(next, tk.Label(
            self.FrameWindow,
            text='',
            fg='#ff3333',
            font=('Arial Black', 20)
        ))

        # 追加するボタンのようなラベルにクリックイベントを設定
        self.insertEntries[next].bind('<1>', lambda event, id=self.index: self.insertEntry_click(event, id))

        # 削除するボタンのようなラベルにクリックイベントを設定
        self.removeEntries[next].bind('<1>', lambda event, id=self.index: self.removeEntry_click(event, id))

        # インデックスマネージャに登録
        self.indexes.insert(next, self.index)

        # 再配置
        self.updateEntries()

    # テキストを取得するボタンを押す
    def GetEntryTextButton_click(self) :
        GetEntry =[]

        # 全てのエントリーウィジェットの内容を配列化
        for i in range(len(self.indexes)) :
            GetEntry.append(self.Entries[i].get())

        # コンソールに表示
        print(GetEntry)

# Tkinter お決まりフレーズ
if __name__ == '__main__' :
    app = App()
    app.mainloop()

動作した感じ

MacOS X 11.6
Python 3.9 で動かしてみました。多分 Win とか他の Python3 のバージョンでも動くと思いますが。

20210923.png

緑色の+ボタンを押すとエントリーウィジェットを直下に追加。
赤色のーボタンを押すと真横のエントリーウィジェットを削除します。
テキストを取得ボタンを押すと、実行中のコンソールに配列として表示します。

なんか、応用すれば色々できそう。

まとめ

なんか、面白いアイディアが思いついたら自由に改変して使ってください。

画面外にはみ出した場合のスクロール実装は下記をご参照ください。
【Python/Tkinter】スクロール可能なFrameを作成するクラス
自分もこれから勉強します。

7
8
3

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
7
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?