この記事を書いた理由
ネットを探してもなかなか見つからなかったため。
需要あると思うんですけどね。意外と。
想定読者
エントリー(テキストボックス)ウィジェットを自由に追加したり、削除したりする、スマホとかでよく見るアレがしたいんじゃあ!
入力項目は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 のバージョンでも動くと思いますが。
緑色の+ボタンを押すとエントリーウィジェットを直下に追加。
赤色のーボタンを押すと真横のエントリーウィジェットを削除します。
テキストを取得ボタンを押すと、実行中のコンソールに配列として表示します。
なんか、応用すれば色々できそう。
まとめ
なんか、面白いアイディアが思いついたら自由に改変して使ってください。
画面外にはみ出した場合のスクロール実装は下記をご参照ください。
【Python/Tkinter】スクロール可能なFrameを作成するクラス
自分もこれから勉強します。