質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
for

for文は、様々なプログラミング言語で使われている制御構造です。for文に定義している条件から外れるまで、for文内の命令文を繰り返し実行します。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

Q&A

解決済

1回答

1003閲覧

Tkinterのfor文内のEntryで取得した値をリストに格納したい

liv_0311

総合スコア2

for

for文は、様々なプログラミング言語で使われている制御構造です。for文に定義している条件から外れるまで、for文内の命令文を繰り返し実行します。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

0グッド

0クリップ

投稿2022/10/18 02:57

前提

Tkinterにおいて、入力した任意の回数だけfor文で生成したEntryウィジェットに入力した値を取得してリストに格納・作成したいです。
for文が実行された時点でリストが作成されてしまうので、値の入力が完了するまで待機してリストに格納することができません。
エンターキーを押したら逐一リストに格納していくといったような動きが可能になればと考えています。

実現したいこと

ここに実現したいことを箇条書きで書いてください。
任意の回数for文で生成されたEntryから、値を取得してリストを作成する。

発生している問題・エラーメッセージ

エラーメッセージはありません。

該当のソースコード

Python

1from tkinter import * 2 3class Application(Frame): 4 def __init__(self, master): 5 super().__init__(master) 6 self.grid() 7 8 master.geometry('1250x1200') 9 master.title('DAアルゴリズムによる学生と研究室のマッチング導出アプリ') 10 master.resizable(False, True) 11 12 self.widget1() 13 self.label_lst = [] 14 self.entry_lst = [] 15 self.button_lst = [] 16 17 def widget1(self): 18 Label(self.master, text='学生の人数を入力 >>').grid(row=0, column=0, pady=5) 19 self.f1 = IntVar(value='') 20 Entry1 = Entry(self.master, textvariable=self.f1, width=5).grid(row=0, column=1, pady=5) 21 22 Label(self.master, text='研究室の数を入力 >>').grid(row=0, column=2, pady=5) 23 self.f2 = IntVar(value='') 24 Entry2 = Entry(self.master, textvariable=self.f2, width=5).grid(row=0, column=3, pady=5) 25 26 Button1 = Button(self.master, text='OK', command=self.btn1_clicked, width=5).grid(row=0, column=4, pady=5) 27 28#例えばEntry1に「5」、Entry2に「3」と入力してButton1を押すと次のbtn1_clickedが動きます。 29 30 def btn1_clicked(self): 31 S = self.f1.get() #S=5 32 C = self.f2.get() #C=3 33 34 for i in range(S): #5回繰り返される 35 label = Label(self.master, text=['学生',i+1,'の希望順に研究室の番号をスペース区切りで入力 >>']).grid(row=i+1, column=0, pady=5) 36#Tkinterに実装する以前のコードで、スペース区切りで入力した値を[int(s) for s in 変数.split()]でリストにしていたため、このようなコードになっています。 37 self.f_s_pref = StringVar(value='') 38 entry = Entry(self.master, textvariable=self.f_s_pref, width=40).grid(row=i+1, column=1, pady=5) 39 self.label_lst.append(label) 40 self.entry_lst.append(entry) 41#5個生成されたentryに順に「1 2 3」「2 3 1」「2 1 3」「1 3 2」「3 2 1」と入力すると、[[1, 2, 3], [2, 3, 1], [2, 1, 3], [1, 3, 2], [3, 2, 1]]というリストが作成されることを可能にしたいです。 42 43 button = Button(self.master, text='OK', command=self.btn2_clicked, width=5).grid(row=S+1, column=2, pady=5) 44 self.button_lst.append(button) 45 46#ここから先のコードは質問に直接関係ないと思われます。 47 48 def btn2_clicked(self): 49 S = self.f1.get() 50 C = self.f2.get() 51 52 for i in range(C): 53 label = Label(self.master, text=['研究室',i+1,'の希望順に学生の番号をスペース区切りで入力 >>']).grid(row=S+1+i, column=0, pady=5) 54 self.f_c_pref = StringVar(value='') 55 entry = Entry(self.master, textvariable=self.f_c_pref, width=40).grid(row=S+1+i, column=1, pady=5) 56 self.label_lst.append(label) 57 self.entry_lst.append(entry) 58 59 button = Button(self.master, text='OK', command=self.btn3_clicked, width=5).grid(row=S+1+i, column=2, pady=5) 60 self.button_lst.append(button) 61 62 def btn3_clicked(self): 63 S = self.f1.get() 64 C = self.f2.get() 65 66 label = Label(self.master, text=['研究室1から順に定員をスペース区切りで入力 >>']).grid(row=S+C+1, column=0, pady=5) 67 self.f_capa = StringVar(value='') 68 entry = Entry(self.master, textvariable=self.f_capa, width=20).grid(row=S+C+1, column=1, pady=5) 69 self.label_lst.append(label) 70 self.entry_lst.append(entry) 71 72 button = Button(self.master, text='OK', command=self.btn4_clicked, width=5).grid(row=S+C+1, column=2, pady=5) 73 self.button_lst.append(button) 74 75 def btn4_clicked(self): 76 S = self.f1.get() 77 C = self.f2.get() 78 79 capacity = [int(s) for s in self.f_capa.get().split()] 80 81 82def main(): 83 root = Tk() 84 app = Application(master = root) 85 app.mainloop() 86 87if __name__ == '__main__': 88 main()

試したこと

Python

1def btn1_clicked(self): 2 S = self.f1.get() 3 C = self.f2.get() 4 5 s_prefs = [] 6 for i in range(S): 7 label = Label(self.master, text=['学生',i+1,'の希望順に研究室の番号をスペース区切りで入力 >>']).grid(row=i+1, column=0, pady=5) 8 self.f_s_pref = StringVar(value='') 9 entry = Entry(self.master, textvariable=self.f_s_pref, width=40).grid(row=i+1, column=1, pady=5) 10 self.label_lst.append(label) 11 self.entry_lst.append(entry) 12 s_pref = [int(s) for s in self.f_s_pref.get().split()] 13 s_prefs.append(s_prefs) 14 15 button = Button(self.master, text='OK', command=self.btn2_clicked, width=5).grid(row=S+1, column=2, pady=5) 16 self.button_lst.append(button)

と記述してみた際には、for文が先にS回実行されるため[[], [], [], ~S個]という空のリストが先に作成されてしまいます。また、

Python

1def btn1_clicked(self): 2 S = self.f1.get() 3 C = self.f2.get() 4 5 for i in range(S): 6 label = Label(self.master, text=['学生',i+1,'の希望順に研究室の番号をスペース区切りで入力 >>']).grid(row=i+1, column=0, pady=5) 7 self.f_s_pref = StringVar(value='') 8 entry = Entry(self.master, textvariable=self.f_s_pref, width=40).grid(row=i+1, column=1, pady=5) 9 self.label_lst.append(label) 10 self.entry_lst.append(entry) 11 12 button = Button(self.master, text='OK', command=self.btn2_clicked, width=5).grid(row=S+1, column=2, pady=5) 13 self.button_lst.append(button) 14 15def btn2_clicked(self): 16 S = self.f1.get() 17 C = self.f2.get() 18 19 s_prefs = [] 20 s_pref = [int(s) for s in self.f_s_pref.get().split()] 21 s_prefs.append(s_pref)

というようにボタン2がクリックされた際にリストを作成する動きにすると、def btn1_clickedのfor文のentryで設定したtextvariable=self.f_s_prefがS-1回上書きされてしまうため、当たり前ですがS回目に入力した値だけが格納されたリスト(ex. [[1, 2, 3])だけが作成されてしまいます。

補足情報(FW/ツールのバージョンなど)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

StringVar, IntVar を格納する変数がループ毎に上書きされています。

tkinter の非ウィジェット (StringVar や PhotoImage) はデストラクタが設定されていて、
変数への参照がなくなるとオブジェクトが破棄されてしまいます。

解決策としては、StringVar, IntVar も他のウィジェット同様にリストへ格納するようにして見て下さい。

エンターキーを押したら逐一リストに格納していくといったような動きが可能になればと考えています。

見落としていたので追記
まずは、StringVar のリストを作成します。(textvariable で使う為に必須)

その後は用途次第で、必要なタイミングで StringVar のリストから値を取り出すか、
即時リストに反映したければ、StringVar オブジェクトの trace メソッドで
値が変更されたタイミングで任意の関数を呼び出す事が出来ます。

python

1#!/usr/bin/env python3.10 2 3import tkinter as tk 4 5def main() -> None: 6 """ 7 8 """ 9 10 root = tk.Tk() 11 12 var_list = [] 13 for _ in range(5): 14 var = tk.StringVar(root) 15 var_list.append(var) 16 entry = tk.Entry(root, textvar=var) 17 entry.pack() 18 19 def onClicked(): 20 result = [ 21 v.get().split(" ") for v in var_list 22 ] 23 print(result) 24 button = tk.Button(root, text="Test", command=onClicked) 25 button.pack() 26 27 root.mainloop() 28 29 30if __name__ == '__main__': 31 main()

補足
textvariable=self.f_s_pref で参照を持たせているように見えますが、ここは特殊なケースで
内部ではオブジェクトのIDの文字列を保持しているのみで、オブジェクトへの参照を持ちません。
また、tkinter は無効な Var オブジェクトを使っているにもかかわらずエラーなどは出しません。

投稿2022/10/18 03:31

編集2022/10/18 03:51
teamikl

総合スコア8664

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

liv_0311

2022/10/18 16:30

ご回答ありがとうございます。 StringVarの性質と、ウィジェット同様にリストを作成して格納していくという考えについて理解しました。 そして、実際に書いていただいたコードを参考にして複数のEntryからの値をリストにすることができました。 初学者のため甘い点があったかとは思いますが、迅速かつ丁寧に回答していただいて感謝しております。 この度はありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問