🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Tkinter

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

while

Whileは多くの言語で使われるコントロール構造であり、特定の条件が満たされる限り一連の命令を繰り返し実行します。

ループ

ループとは、プログラミングにおいて、条件に合致している間、複数回繰り返し実行される箇所や、その制御構造を指します

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

PyCharm

エディター・開発ツール

Q&A

解決済

1回答

8837閲覧

Tkinterを何度も使おうとするとエラーが出る

YUMA-NAGAO

総合スコア41

Tkinter

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

while

Whileは多くの言語で使われるコントロール構造であり、特定の条件が満たされる限り一連の命令を繰り返し実行します。

ループ

ループとは、プログラミングにおいて、条件に合致している間、複数回繰り返し実行される箇所や、その制御構造を指します

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

PyCharm

エディター・開発ツール

0グッド

0クリップ

投稿2019/10/29 06:12

編集2019/12/24 04:41

前提・実現したいこと

Pythonでいいえが押されるまで質問するシステムを作っています。
Tkinterを使い何度も分岐をする機能を実装中に以下のエラーメッセージが発生しました。

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

エラーメッセージ return self.tk.call('wm', 'geometry', self._w, newGeometry) _tkinter.TclError: can't invoke "wm" command: application has been destroyed

該当のソースコード

import tkinter from tkinter import messagebox # ウインドウ root = tkinter.Tk() root.withdraw() messagebox.showinfo('', '開始!!!!') def ajust_moving(): # データ数入力 root.deiconify() root.title(u"調整") root.geometry("250x120") Static1 = tkinter.Label(text=u'+か-を入れてください!') Static1.pack() EditBox1 = tkinter.Entry() EditBox1.insert(tkinter.END, '+') EditBox1.pack() Static2 = tkinter.Label(text=u'100単位で数字を入れてください') Static2.pack() EditBox2 = tkinter.Entry() EditBox2.insert(tkinter.END, '100') EditBox2.pack() aaa = tkinter.Button(root, text='確定', width='10', command=root.destroy) aaa.pack() value = EditBox1.get() nuaa = EditBox2.get() root.mainloop() anka = 'm:1' + value + 'p' + nuaa + '\r\n' # 文字列の結合 # 相対移動文字列を作る # 関数内関数作ってもいいんじゃね? root.geometry("0x0") # ウィンドウのタイトルバーを消す(Windows用の設定) root.overrideredirect(1) while True: OneMore_adjust = messagebox.askyesno('Adjusts_Onemore', 'もう一度調整しますか?') if OneMore_adjust: ajust_moving() else: break root = tkinter.Tk() root.withdraw() messagebox.showinfo('', '完了!!') #追記のソースコードここから import tkinter from tkinter import messagebox # ウインドウ root = tkinter.Tk() # root.withdraw() def on_start(): messagebox.showinfo('', '開始!!!!') # 次にmainloop内から main_proc() 関数を呼ぶ root.after(0, main_proc) # 0秒後にmain_procという関数を呼ぶという意味 def main_proc(): # ここで設定Windowを Toplevel Widget にて作成 global top top = tkinter.Toplevel(root) top.deiconify() top.title(u"調整") top.geometry("250x120") # 以下に 設定画面を作成(省略) Static1 = tkinter.Label(top, text=u'+か-を入れてください!') Static1.pack() EditBox1 = tkinter.Entry(top) EditBox1.insert(tkinter.END, '+') EditBox1.pack() Static2 = tkinter.Label(top, text=u'100単位で数字を入れてください') Static2.pack() EditBox2 = tkinter.Entry(top) EditBox2.insert(tkinter.END, '100') EditBox2.pack() button = tkinter.Button(top, text='確定', width='10',command=on_closing()) button.pack() sign = EditBox1.get() value = EditBox2.get() root.mainloop() anka = 'm:1' + sign + 'p' + value + '\r\n' # 文字列の結合 # 相対移動文字列を作る # 関数内関数作ってもいいんじゃね? # ser.write(bytes(anka, 'UTF-8')) # ser.write(b'g:\r\n') print(anka) # Toplevel Widgetが閉じられるときは on_close()関数を呼ぶ def on_closing(): top.destroy() # 確認用ダイアログを出す onemore = messagebox.askyesno('Adjusts_Onemore', 'もう一度調整しますか?') if onemore: # 再度 mainloop内から main_proc() 関数を呼ぶ root.after(0, main_proc) else: # 完了ダイアログを出す messagebox.showinfo('', '完了!!') # rootを破棄(これでmainloopを抜けるはず) root.destroy() # 最初にmainloop内から on_start() 関数を呼ぶ root.after(0, on_start) root.mainloop()

試したこと

while文にする前は自分が想像していた動作が実現できました。
あと、Tkinterは何度も実行する仕様ではないということも調べた結果わかりました。

###教えていただきたいこと
最初と最後は、withdraw()で隠したいです。
関数を実行するときは、表示したいとおもっているため 、
deiconify()を使っています。

tkinterでタブを削除した後
While文内のif文を何度も実行してうまく挙動させるに葉どうしたらいいのか?
もしくは、while文を使わないでif文の挙動を何回もできるようにしたいです。
もしくはTkinterを使わないでも実装できるやり方を知りたいです。

#解決コード
サブウィンドウを作成し、それを何度も破壊することでメインウィンドウを削除しないでもよくなった。
※回答欄から転載

Python

1import tkinter 2from tkinter import messagebox 3 4# ウインドウ 5root = tkinter.Tk() 6root.withdraw() 7 8def on_start(): 9 messagebox.showinfo('', '開始!!!!') 10 # 次にmainloop内から main_proc() 関数を呼ぶ 11 root.after(0, main_proc) 12 13def main_proc(): 14 # ここで設定Windowを Toplevel Widget にて作成 15 global top 16 top = tkinter.Toplevel(root) 17 top.deiconify() 18 top.title(u"調整") 19 top.geometry("250x120") 20 # 以下に 設定画面を作成(省略) 21 22 # Toplevel Widgetが閉じられるときは on_close()関数を呼ぶ 23 top.protocol("WM_DELETE_WINDOW", on_closing) 24 25def on_closing(): 26 # Toplevel Widgetを破棄 27 top.destroy() 28 # 確認用ダイアログを出す 29 onemore = messagebox.askyesno('Adjusts_Onemore', 'もう一度調整しますか?') 30 if onemore: 31 # 再度 mainloop内から main_proc() 関数を呼ぶ 32 root.after(0, main_proc) 33 else: 34 # 完了ダイアログを出す 35 messagebox.showinfo('', '完了!!') 36 # rootを破棄(これでmainloopを抜けるはず) 37 root.destroy() 38 39# 最初にmainloop内から on_start() 関数を呼ぶ 40root.after(0, on_start) 41root.mainloop() 42

##注意点
commandで関数を指定するときは、
command=on_closing()
ではなく、
command=on_closing
と記述する。
commandパラメータに渡すのは、「関数」を渡す。
括弧つきで記述すると、その場で関数が実行され、その戻り値がcommandパラメータに渡すという意味になってしまうので、注意が必要。

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

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

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

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

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

t_obara

2019/10/29 08:56

どのような動きを期待しているのでしょうか。 基本的なこととして、UIプログラムにおいて、処理の制御をwhileで行うべきではありません。ウィンドウの描画処理などのループがroot.mainloop で行う必要があり、whileが入ることでそれらを阻害するからです。
YUMA-NAGAO

2019/10/29 23:32

何度も、while文内のif文を繰り返す動きを実装したいです。 色々試行錯誤した結果、while文はいらなくなりました。 他の処理で何度もwhile文内のif文を実行するからです。
guest

回答1

0

ベストアンサー

ジャストアイデアです。

root = tkinter.Tk() を何度も生成・破棄を繰り返すのではなく、root は一度だけ生成しておいて(当然mainloopも一度だけ呼ぶ)、別ウィンドウ tkinter.Toplevel(root)の生成・破棄を繰り返すというのはどうでしょうか。

以下は簡単なテストコードです。

Python

1import tkinter 2from tkinter import messagebox 3 4# ウインドウ 5root = tkinter.Tk() 6root.withdraw() 7 8def on_start(): 9 messagebox.showinfo('', '開始!!!!') 10 # 次にmainloop内から main_proc() 関数を呼ぶ 11 root.after(0, main_proc) 12 13def main_proc(): 14 # ここで設定Windowを Toplevel Widget にて作成 15 global top 16 top = tkinter.Toplevel(root) 17 top.deiconify() 18 top.title(u"調整") 19 top.geometry("250x120") 20 # 以下に 設定画面を作成(省略) 21 22 # Toplevel Widgetが閉じられるときは on_close()関数を呼ぶ 23 top.protocol("WM_DELETE_WINDOW", on_closing) 24 25def on_closing(): 26 # Toplevel Widgetを破棄 27 top.destroy() 28 # 確認用ダイアログを出す 29 onemore = messagebox.askyesno('Adjusts_Onemore', 'もう一度調整しますか?') 30 if onemore: 31 # 再度 mainloop内から main_proc() 関数を呼ぶ 32 root.after(0, main_proc) 33 else: 34 # 完了ダイアログを出す 35 messagebox.showinfo('', '完了!!') 36 # rootを破棄(これでmainloopを抜けるはず) 37 root.destroy() 38 39# 最初にmainloop内から on_start() 関数を呼ぶ 40root.after(0, on_start) 41root.mainloop()

投稿2019/10/29 09:41

magichan

総合スコア15898

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

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

YUMA-NAGAO

2019/10/30 02:41

返答ありがとうございます。 やってみたところ、新たな疑問が生まれました。 aaaのボタンのcommandにon_closing()を入れてみたのですが、確定ボタンが表示されないで消えてしまいます。 どうすれば、解決できるでしょうか? やってみたコードを追記しておきます。
magichan

2019/10/30 02:50

もしかして command=on_closing() と記述してませんか? commandパラメータに渡すのは『関数』ですので command=on_closing のように記述します。(括弧をつけない) 最初ように括弧付きで記述すると、その場で on_closing() 関数が実行され、その戻り値がcommandパラメータに渡すという意味になるので注意が必要です。
YUMA-NAGAO

2019/10/30 04:15

なるほど!!! ()括弧をつけると、その場で実行されるんですね!!! commandは関数の名前を与えるのは初めて知りました! ありがとうございました!!! こちらのコードを使うことで、該当部分を実装することが出来ました! ありがとうございました!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問