#前提・実現したいこと
Tkinterで確定ボタンを押したときに、テキストファイルにデータを書きこむ
下記ソースコードに記載されているconnectに入っているデータをテキストファイルに書き込みたいです。
#既に出来ている機能
1、テキストファイルに上書きする機能
2、Tkinterを使い、何度も同じ動作を繰り返す機能
この二つが出来ています。
今回は、それらを組み合わせるのが最終目的です。
#試したこと
root.mainloopの場所を変更するということを試しました。
前回の質問を基にしてテキストファイルへの書き込み方法を追記しました。
しかし、思ったような動作が出来ません。
その結果、
1、エラーが発生し、テキストファイルにtkinterに打ち込んだ時の値が、書き込める。
2、エラーが発生し、テキストファイルに打ち込んだ時の値が書き込めない。
3、エラーは発生しないが、tkinterに打ち込んだ時の値が変更されない
という状態になっています。
ググった時のキーワードは「Python tkinter textファイル書き込み」などです。
#発生している問題・エラーメッセージ
エラーメッセージがあるもの、エラーメッセージを記述します。
エラーメッセージ 1
Python
1 2Traceback (most recent call last): 3 File "C:/Users/Anaconda3/envs/py3.7/BrightnessControl.py", line 75, in <module> 4 AjustLight() 5 File "C:/Users/Anaconda3/envs/py3.7/BrightnessControl.py", line 72, in AjustLight 6 root.after(0, Light()) 7 File "C:/Users/Anaconda3/envs/py3.7/BrightnessControl.py", line 39, in Light 8 one = EditBox1.get() 9 File "C:\Users\nagao\Anaconda3\envs\py3.7\lib\tkinter\__init__.py", line 2682, in get 10 return self.tk.call(self._w, 'get') 11_tkinter.TclError: invalid command name ".!toplevel.!entry"
エラーメッセージ 2
Python
1 Traceback (most recent call last): 2 File "C:/Users/Anaconda3/envs/py3.7/BrightnessControl.py", line 75, in <module> 3 AjustLight() 4 File "C:/Users/Anaconda3/envs/py3.7/BrightnessControl.py", line 72, in AjustLight 5 root.after(0, Light()) 6 File "C:/Users/Anaconda3/envs/py3.7/BrightnessControl.py", line 39, in Light 7 one = EditBox1.get() 8 File "C:\Users\nagao\Anaconda3\envs\py3.7\lib\tkinter\__init__.py", line 2682, in get 9 return self.tk.call(self._w, 'get') 10_tkinter.TclError: invalid command name ".!toplevel.!entry"
#該当のソースコード
Python
1import tkinter 2from tkinter import messagebox 3 4 5def AjustLight(): 6 def Light(): 7 # ここで設定Windowを Toplevel Widget にて作成 8 global top 9 global connect 10 11 top = tkinter.Toplevel(root) 12 top.deiconify() 13 top.title(u"調整") 14 top.geometry("250x150") 15 Static1 = tkinter.Label(top, text=u'光量の調整が可能です!') 16 Static1.pack() 17 Static2 = tkinter.Label(top, text=u'数字を入れてください') 18 Static2.pack() 19 EditBox1 = tkinter.Entry(top) 20 EditBox1.insert(tkinter.END, '0') 21 EditBox1.pack() 22 EditBox2 = tkinter.Entry(top) 23 EditBox2.insert(tkinter.END, '1') 24 EditBox2.pack() 25 EditBox3 = tkinter.Entry(top) 26 EditBox3.insert(tkinter.END, '2') 27 EditBox3.pack() 28 EditBox4 = tkinter.Entry(top) 29 EditBox4.insert(tkinter.END, '3') 30 EditBox4.pack() 31 32 button = tkinter.Button(top, text='確定', width='10', command=FinishEvent) 33 # command=で入れた関数に()があると、関数がうまく使うことが出来ない。 34 # (正確に言うと、起動したときに実行されてしまうので、ダメ) 35 button.pack() 36 37 root.mainloop() 38 one = EditBox1.get() 39 second = EditBox2.get() 40 third = EditBox3.get() 41 fourth = EditBox4.get() 42 43 connect = '0,' + one + ',' + second + ',' + third + ',' + fourth 44 45 path = r"C:\Users\Desktop\test.txt" 46 with open(path, "w") as f: 47 f.write(connect) 48 with open(path, "r") as f: 49 reading=f.read() 50 print(reading) 51 52 def FinishEvent(): 53 top.destroy() 54 # toplevel wigget(サブウィンドウ)を破壊する 55 ajust_onemore = messagebox.askyesno('Adjusts_Onemore', 'もう一度調整しますか?') 56 # 確認用ダイアログを出す 57 # 調整用のやつ 58 if ajust_onemore: 59 # 再度 mainloop内から ajust_moving() 関数を呼ぶ 60 root.after(0, Light) 61 else: 62 # 完了ダイアログを出す 63 messagebox.showinfo('', '完了!!') 64 root.destroy() 65 # rootを破棄(これでmainloopを抜けるはず) 66 67 root = tkinter.Tk() 68 root.withdraw() 69 root.after(0, Light()) 70 71 72AjustLight() 73 74print(connect) 75
#教えていただきたいこと
3点あります。
######今回の質問について
1、どのようにサンプルコードを変えればいのか?
2、サンプルコードを作成した過程(ググった時のキーワードや解決までの考え方など)
3、コードを簡潔にする方法
これらを教えていただきたいです!
自力で解決できるようになりたいので!
#回答を基に修正したコード【その1】
このコードを使うことで思った通りの動作をすることが出来た。
値を入れるボックスをglobal宣言したことで、コールバックした関数内で使えるようになりました。
このコードの実装の仕方は、少しいかがなものかと思います。
処理を変えないで、綺麗なコードにするやり方を教えていただきたいです。
Python
1import tkinter 2from tkinter import messagebox 3 4 5def AjustLight(): 6 7 8 def Light(): 9 # ここで設定Windowを Toplevel Widget にて作成 10 global top 11 global EditBox1 12 global EditBox2 13 global EditBox3 14 global EditBox4 15 top = tkinter.Toplevel(root) 16 top.deiconify() 17 top.title(u"調光") 18 top.geometry("250x150") 19 # 以下に 設定画面を作成(省略) 20 Static1 = tkinter.Label(top, text=u'光量の調整が可能です!') 21 Static1.pack() 22 Static2 = tkinter.Label(top, text=u'0-255の間で1単位で数字を入れてください') 23 Static2.pack() 24 EditBox1 = tkinter.Entry(top) 25 EditBox1.insert(tkinter.END, '0') 26 EditBox1.pack() 27 EditBox2 = tkinter.Entry(top) 28 EditBox2.insert(tkinter.END, '255') 29 EditBox2.pack() 30 EditBox3 = tkinter.Entry(top) 31 EditBox3.insert(tkinter.END, '255') 32 EditBox3.pack() 33 EditBox4 = tkinter.Entry(top) 34 EditBox4.insert(tkinter.END, '0') 35 EditBox4.pack() 36 37 38 button = tkinter.Button(top, text='確定', width='10', command=FinishEvent) 39 # command=で入れた関数に()があると、関数がうまく使うことが出来ない。 40 # (正確に言うと、起動したときに実行されてしまうので、ダメ) 41 button.pack() 42 43 root.mainloop() 44 45 def FinishEvent(): 46 one = EditBox1.get() 47 second = EditBox2.get() 48 third = EditBox3.get() 49 fourth = EditBox4.get() 50 global connect 51 connect = '0,' + one + ',' + second + ',' + third + ',' + fourth 52 53 path = r"C:\Users\Desktop\test.txt" 54 with open(path, "w") as f: 55 f.write(connect) 56 with open(path, "r") as f: 57 reading = f.read() 58 print(reading) 59 60 top.destroy() 61 # toplevel wigget(サブウィンドウ)を破壊する 62 ajust_onemore = messagebox.askyesno('Adjusts_Onemore', 'もう一度調整しますか?') 63 # 確認用ダイアログを出す 64 # 調整用のやつ 65 if ajust_onemore: 66 # 再度 mainloop内から ajust_moving() 関数を呼ぶ 67 root.after(0, Light) 68 else: 69 # 完了ダイアログを出す 70 messagebox.showinfo('', '完了!!') 71 root.destroy() 72 # rootを破棄(これでmainloopを抜けるはず) 73 74 root = tkinter.Tk() 75 root.withdraw() 76 77 root.after(0, Light()) 78 79 80AjustLight() 81 82print(connect) 83
#回答を基に修正したコード【完成版】
回答を基に必要な動作を加えたコードです。
入力規則などについても教えていただいて、感謝です。
Python
1import tkinter 2from tkinter import messagebox 3 4 5def AjustLight(): 6 setting_values = {} 7 top = None 8 9 def Light(): 10 # ここで設定Windowを Toplevel Widget にて作成 11 nonlocal top 12 13 14 # Entryへの入力値のValidationコマンド 15 # この中でデータをdictに格納しておく 16 def validation(name, word): 17 # 空か数値以外の入力は不可 18 result = (len(word) == 0) or word.isnumeric() 19 # 問題なければ値をconnectに格納 20 if result: 21 setting_values[name.split('.')[-1]] = word 22 23 return result 24 25 top = tkinter.Toplevel(root) 26 top.deiconify() 27 top.title(u"調整") 28 top.geometry("250x150") 29 top.protocol('WM_DELETE_WINDOW', lambda: root.destroy()) 30 vcmd = (top.register(validation), '%W', '%P') 31 Static1 = tkinter.Label(top, text=u'光量の調整が可能です!') 32 Static1.pack() 33 Static2 = tkinter.Label(top, text=u'数字を入れてください') 34 Static2.pack() 35 EditBox1 = tkinter.Entry(top, name='num0', validate='key', validatecommand=vcmd) 36 EditBox1.insert(tkinter.END, '0') 37 EditBox1.pack() 38 EditBox2 = tkinter.Entry(top, name='num1', validate='key', validatecommand=vcmd) 39 EditBox2.insert(tkinter.END, '0') 40 EditBox2.pack() 41 EditBox3 = tkinter.Entry(top, name='num2', validate='key', validatecommand=vcmd) 42 EditBox3.insert(tkinter.END, '0') 43 EditBox3.pack() 44 EditBox4 = tkinter.Entry(top, name='num3', validate='key', validatecommand=vcmd) 45 EditBox4.insert(tkinter.END, '0') 46 EditBox4.pack() 47 button = tkinter.Button(top, text='確定', width='10', command=FinishEvent) 48 button.pack() 49 50 def Save(file): 51 nonlocal setting_values 52 # connectに格納している値をリスト化 53 val = [setting_values[f'num{i}'] for i in range(4)] 54 # print(val) 55 # 上記のリストをファイルに書き込む 56 with open(file, "w") as f: 57 f.write(f'0,{val[0]},{val[1]},{val[2]},{val[3]}') 58 with open(file, 'r') as f: 59 print(f.read()) 60 # 意図した値になっているかの確認 61 62 def FinishEvent(): 63 # ここでセーブする 64 file_path=r'C:\Users\Desktop\test.txt' 65 Save(file_path) 66 top.destroy() 67 # toplevel wigget(サブウィンドウ)を破壊する 68 ajust_onemore = messagebox.askyesno('Adjusts_Onemore', 'もう一度調整しますか?') 69 # 確認用ダイアログを出す 70 # 調整用のやつ 71 if ajust_onemore: 72 # 再度 mainloop内から Light関数を呼ぶ 73 root.after(0, Light) 74 else: 75 # 完了ダイアログを出す 76 messagebox.showinfo('', '完了!!') 77 root.destroy() 78 # rootを破棄(これでmainloopを抜けるはず) 79 80 root = tkinter.Tk() 81 root.withdraw() 82 root.after(0, Light()) 83 root.mainloop() 84 return setting_values 85
#参考URL
知らないことを調べた。
Python の isnumeric() メソッド
tkinterのEntryにvalidationを実装する part 1 基底クラスを作る。
回答3件
あなたの回答
tips
プレビュー