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

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

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

PyAutoGUIは、Windows、Mac OS、Linuxに対応した、Python用のGUI自動化ライブラリです。

Python 3.x

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

Tkinter

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

Python

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

Q&A

解決済

2回答

4977閲覧

Python tkinter でボタンの選択状態を保持したい

per_

総合スコア41

PyAutoGUI

PyAutoGUIは、Windows、Mac OS、Linuxに対応した、Python用のGUI自動化ライブラリです。

Python 3.x

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

Tkinter

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

Python

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

1グッド

0クリップ

投稿2020/08/07 03:05

前提・やりたいこと

Python tkinter を用いて、

  • ランダムに画像と質問を表示する(画像表示は今回のコードでは割愛)
  • 4つの選択肢から回答を選んでもらう
  • 回答に基づいて処理をする(内容は割愛、末尾のコードではそのままprintさせています)
  • 次の質問と画像を表示する
  • 終了するのボタンを押すまで処理を続ける

というプログラムを作っています。

各々のボタンを行き来するためにはTabShift + Tabで行いますが、
上下キーで選択肢を移動させ、エンターキーで確定させたいため、
キーを押下したときにPyautoguiで操作するイベントを設定しています。

実現させたい挙動

上下キーで選択し、Enterキーで確定したあと
次の質問と画像が表示されたときに
直前に選んでいた選択肢の状態のままにさせたいのですが、

python

1def question_set_close(): 2 f.destroy()

上記の関数でフレームを消していることが原因か、
そう思う思わないのいずれかのボタンを押した時点で選択状態が解除されてしまいます。
しかし、フレームを消さない場合、画像と質問が下にどんどん連なってしまいます。

イメージ説明

質問

上記の通り、選択状態を維持したままにすることはできるでしょうか?
みなさまの知識をお借り出来ればと思います。



コード(全体)

python

1 2#!python3.7 3 4# 標準ライブラリ 5import random 6 7# インポートライブラリ 8import pyautogui 9import tkinter as tk 10import tkinter.font as tkFont 11from tkinter import messagebox as msgbox 12 13 14pictag = "" 15alist = ['そう思う','やや思う','あまり思わない','思わない'] 16tag_prop = '' 17 18question = ['A','B','C','D','E','F','G','H','I','J','K'] 19 20 21class TypeButton(tk.Button): 22 def __init__(self, master, label, qtype, color_code): 23 tk.Button.__init__(self, master, text=qtype, bg=color_code, command=self.btn_click) 24 self.label = label 25 self.qtype = qtype 26 self.color_code = color_code 27 28 def btn_click(self): 29 global tag_prop 30 tag_prop = self.qtype 31 if self.qtype == '違う質問を選ぶ': 32 changeText() 33 elif self.qtype == '終了する': 34 question_set_close() 35 global exitflg 36 exitflg = True 37 else: 38 print(tag_prop) 39 question_set_close() 40 41 42class Frame(tk.Frame): 43 def __init__(self, master=None): 44 global pictag 45 global question 46 47 tk.Frame.__init__(self, master) 48 self.master.title('回答してくだださい') 49 self.option_add('*font', ('FixedSys', 16)) 50 f_button = tk.Frame(self) 51 f_button.pack(side=tk.LEFT, padx=5, pady=5) 52 53 pictag = random.choice(question) 54 self.qtxt = tk.StringVar() 55 self.qtxt.set("これは {} ですか?".format(pictag)) 56 label = tk.Label(self, textvariable=self.qtxt) 57 label.configure(font=('FixedSys',30)) 58 label.pack(pady=5,side=tk.TOP ,fill=tk.X) 59 60 for name in alist: 61 b = TypeButton(f_button, label, name, '#ecffff') 62 b.pack(pady=5,fill=tk.X,side=tk.TOP) 63 another = TypeButton(f_button, label, '違う質問を選ぶ', '#d3ffc2') 64 another.pack(pady=25,fill=tk.X,side=tk.TOP) 65 buttonquit = TypeButton(f_button, label, '終了する', '#fec7ef') 66 buttonquit.pack(pady=25,fill=tk.X,side=tk.TOP) 67 68 69def changeText(): 70 global pictag 71 pictag = random.choice(question) 72 f.qtxt.set("これは {} ですか?".format(pictag)) 73 74def question_set_close(): 75 f.destroy() 76 root.quit() 77 78 79 80# 上下キーとエンターキーが押されたときの処理 81def upKey(event): 82 pyautogui.hotkey('shift', 'tab') 83 84def downKey(event): 85 pyautogui.hotkey('tab') 86 87def enterKey(event): 88 pyautogui.hotkey('space') 89 90 91if __name__ == '__main__': 92 root = tk.Tk() 93 exitflg = False 94 95 while exitflg == False: 96 f = Frame() 97 root.bind('<Up>', upKey) 98 root.bind('<Down>', downKey) 99 root.bind('<Return>', enterKey) 100 f.pack() 101 f.mainloop() 102 103 if tag_prop == '': 104 exitflg = True 105 tag_prop = '' 106 107 else: 108 root = tk.Tk() 109 root.withdraw() 110 if tag_prop == '': 111 msgbox.showinfo('終了します', 'ご協力ありがとうございました。') 112 113
teamikl👍を押しています

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

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

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

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

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

guest

回答2

0

原因: ボタンをクリックする度に、毎回 Tk を起動して終了しているので、

対策: Tk() 作成と mainloop() を呼び出すのは一度のみにして、
一度生成したGUI部品(ウィジェット)を再利用するように変更が必要です。

  • 問題文を設定する部分を別の関数に切り出します。

 注意点: この関数内では、ラベルウィジェットは生成しません。

  • ボタンクリック時に、

 回答があった場合の処理と、新たな問題文を設定する関数を呼びます。

この変更により、ボタン・ウィジェットは再生成しなくなるので、
結果として、選択状態は維持されるようになります。


  • root.quit や destroy は、終了時以外では不要になります。

投稿2020/08/07 04:10

編集2020/08/07 04:15
teamikl

総合スコア8681

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

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

per_

2020/08/17 02:09

ご回答ありがとうございます。 ウィジェットを再利用するという頂いた回答を元に、root.quit や destroy をさせないコードを試みてみます。 今回は、直近で変更が効いた別の方の回答をベストアンサーとさせていただきましたが、とても参考になりました。
teamikl

2020/08/17 03:23

現状のコードからは、大きな変更になるかもしれませんが、 「毎回 Tk を起動して終了」をなくすことで、選択状態の保存以外にも 次の質問に移る際のちらつき(一瞬ウィンドウが閉じてから再度表示) も解消できるので、余裕があるなら検討してみてください。 他にも、 ライブラリ自身が、Tk()を複数回作成するような想定になってない為、 複数のウィンドウを作ったりする場合、問題が起こりやすくなったりします。
per_

2020/08/17 10:45

teamikl様、コメントありがとうございます。 問題文のラベルウィジェットの再利用は出来ていたのですが、画像を読み込んでいるラベル(質問では割愛した部分のコードです)の処理が分からず毎回フレームごと破棄していました。 ご意見を参考に調べまして、回答のボタンを押した際に、 imagelabel.configure(image=新しい画像) とする関数を別で組み込むことで、quit や destroy をしないコードにすることができました。 今後を考えればこちらの方法の方が汎用性が高そうですね...ありがとうございました。
guest

0

ベストアンサー

.focus_set()でフォーカスがセットされた状態に出来ます。

回答した際に何番目のボタンを押下したかのか変数として残しておくなど
回答後の処理がどの様なものかはわかりませんが、判定要素は様々作れると思うので
組み込んでいく際にご参考にしてください。

python

1for e, name in enumerate(alist): 2 b = TypeButton(f_button, label, name, '#ecffff', e) 3 b.pack(pady=5,fill=tk.X,side=tk.TOP) 4 if e == 前回押したボタン: 5 b.focus_set()

投稿2020/08/07 04:24

nto

総合スコア1438

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

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

per_

2020/08/17 02:05

ご回答ありがとうございます。とても参考になりました。 ntoさんの回答では数字で判定していますが、ボタンのテキストをそのまま判定要素とすることで解決しました。 プログラムの変更を最小限に、目的のことが達成できました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問