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

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

新規登録して質問してみよう
ただいま回答率
86.02%
Python 3.x

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

Tkinter

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

Q&A

解決済

ウィジェットのフォーカスをイベント切り替えたい

shinobuKouno
shinobuKouno

総合スコア23

Python 3.x

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

Tkinter

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

2回答

0グッド

1クリップ

200閲覧

投稿2022/11/11 09:26

前提

ウィジェットのフォーカスをイベント後に次のウィジェットへ移動したい

↓のコードではリストにウィジェットを格納し、イベントハンドラにリストのインデックスを渡し
イベントの処理が発生した後に、次のリストインデックスのウィジェットにフォーカス
を当てようと思いましたが駄目でした。
イベント後に次(ウィジェット作成時に順番)のウィジェットへフォーカスを移す方法を
教えてください

該当のソースコード

import tkinter as tk class TopMenu: w_list = [] def focus_in_event(event,code): event.widget['bg'] = '#5CC7B2'       #最後まで行ったら最初に戻る if code == 4: code = 0 else: code += 1 print(acc) TopMenu.w_list[code].focus_set() root = tk.Tk() root.title("test_a") root.geometry("670x400") for i in range(5): txt_a = tk.Entry(root) txt_a.pack() txt_a.bind("<FocusIn>", focus_in_event(i)) txt_a.bind("<FocusOut>", focus_out_event) w_list.append(txt_a) root.mainloop()

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

Python 3.10.5
Tkinter 8.6

よろしくお願いします。

以下のような質問にはグッドを送りましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

グッドが多くついた質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

teamikl

2022/11/12 05:03

実行できるコードを掲載してください。 focus_out_event が未定義です。 コードが期待通りに動作したとしても、 フォーカス In イベント内に次のフォーカスへ移動とすると フォーカス In/Out イベントが永遠と呼ばれ続ける事になるので、 設問自体に無理があります。 やりたいことは、例えば、 フォーカスOut 時や Tab や Enter キーを押したときの 次の入力へのフォーカス移動ではありませんか?
shinobuKouno

2022/11/14 05:25

すみません。変数(i)と(code)を消し忘れておりました >>フォーカス In/Out イベントが永遠と呼ばれ続ける事になるので 今回のテストではIn/Outを永遠に続けるのが目的です。実際にはイベントのあるEntryの後にはイベントの無いEntryを設定する予定なのですが、 For分で作ったウィジェットのフォーカス移動手段を知りたかったため質問させていただきました import tkinter as tk class TopMenu: w_list = [] def focus_in_event(event): acc = 'abcdef' event.widget['bg'] = '#5CC7B2' event.widget.delete(0,tk.END) event.widget.insert(tk.END, acc) #TopMenu.w_list[???].focus_set() # ←ここで次のEntryにフォーカスを移せばよいのかと考えました def focus_out_event(event): event.widget['bg'] = '#FFFFFF' root = tk.Tk() root.title("test_a") root.geometry("670x400") for i in range(5): txt_a = tk.Entry(root) txt_a.pack() txt_a.bind("<FocusIn>", focus_in_event) txt_a.bind("<FocusOut>", focus_out_event) w_list.append(txt_a) root.mainloop()
teamikl

2022/11/14 06:42

>今回のテストではIn/Outを永遠に続けるのが目的です。 ここの認識に齟齬がありそうです。 「IN/Out が永遠に続けられる」というのは1回のイベントで In/Out/In/Out が永遠と連続して発生し、 フォーカスが定まらない状態になってしまいます。(ウィンドウは応答なしになります) 1: FocusIn で 次の entry へフォーカスを移す 2: 次の entry の FocusIn が発生。focus_in_entry では次の entry へフォーカスを移す 3: 前の entry の FocusOut も発生 4. 次の次の entry の FocusInt が発生。。以下ループ ちなみに、focus_out_event でフォーカスを移すと Tab キーでの移動を阻害してしまうので、UIとして使い辛くなります。 ループ対策として、入力欄が空ならフォーカス移動をしないなどの対策が必要です。 利便性の為に次の入力欄へフォーカスを移すのではなく、 実験的にフォーカスが永遠と移動するアニメーションをやりたいという事でしょうか? その場合は、また全然話が変わってきます。

回答2

1

ベストアンサー

イベントに関しては、質問した通り
Entry のFocusIn/FocusOut イベントをトリガーにするのは、無理があると思うので、
(自動で移動した時の FocusIn と マウスでクリックした時の FocusIn の挙動も扱いが変わってきて、
イベントの複雑なデバッグが発生してしまいます)

次の入力欄へのフォーカスの移動について回答します。

tkinter では元々 tab キーによる入力フォーカスの移動が可能で、
tk_nextFocus により、次の入力可能ウィジェットを所得出来ます。
末尾に到達すると自動的に頭に戻ります。

python

1import tkinter as tk 2from tkinter import ttk 3 4root = tk.Tk() 5style = ttk.Style() 6style.theme_use("default") 7style.configure("TEntry", 8 fieldbackground='white') 9style.map("TEntry", 10 fieldbackground=[('focus', '#eeffff')]) 11 12def nextFocus(event): 13 event.widget.tk_focusNext().focus() 14 15for num in range(5): 16 entry = ttk.Entry(root) 17 entry.bind("<Return>", nextFocus) # Enter キーを押したとき 18 entry.pack() 19 20root.mainloop()

FocusIn/FocusOut の色変更は、ttk.Entry のスタイルに変更
(ttk.Entry では宣言的に色など定義のが可能。
但し、一部 entry["bg"] オプション等は使えなくなります)


リストに入れたウィジェットのフォーカスのループについて

方法1: itertools.cycle を使った無限リスト

import itertools w_list = [] # ここで Entry widgetを追加 (w_list.append) w_iter = itertools.cycle(w_list) # 必ず要素の追加後に呼び出す def nextFocus(event): next(w_iter).focus()

方法2: カウンタを使う方法

リストの要素数で割った余りを用いると、
「末尾を超えた時に頭に戻る」というロジックをより簡潔に記述できます。

python

1 2count = 0 3 4def nextFocus(event): 5 global count 6 count = (count + 1) % len(w_list) 7 w_list[count].focus()

デメリット: 外部でカウントの為の変数を管理しなければなりません。
クラスを使う場合は global ではなくインスタンス変数に。

ちなみに、この方法での実装は不具合があって、
マウスカーソルで他の Entry をクリックしてフォーカスを移動した場合、
基準となるウィジェットがずれるので、期待されるような順序になりません。

イベント内で現在のウィジェットの順序を所得して、次のウィジェットを判別する必要があります。

改善例

python

1def focusNext(event): 2 index = w_list.index(event.widget) 3 w_list[(index + 1) % len(w_list)].focus()

投稿2022/11/14 07:29

編集2022/11/14 15:16
teamikl

総合スコア8557

spoofy_dragon👍を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

0

ありがとうございます。大変勉強になりました。

投稿2022/11/14 10:23

shinobuKouno

総合スコア23

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

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

ただいまの回答率
86.02%

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

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

質問する

関連した質問

同じタグがついた質問を見る

Python 3.x

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

Tkinter

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