複数のエントリ(テキストボックス)を配置するとき、バーコードリーダーでバーコードにある内容を入力したら自動で次のエントリにフォーカスが当たるようにしたいのですが下のソースコードでe2.focus_set()をどのように記述すれば良いでしょうか?
(使っているバーコードはHR-100です。取扱説明書を見る限り、読み取ったデータの末尾に対しての付加コードはなさそうです。Tabの付加コードがあればバーコードリーダーに設定すればいいので、ソースファイル上で考える必要はないのですが・・・)
import tkinter as tk win = tk.Tk() # e1へのバーコードリーダーでの入力直後、e1からe2へフォーカスを切り替えたい e1 = tk.Entry(win) e1.grid() e2 = tk.Entry(win) e2.grid() b = tk.Button(win, text="click") b.grid() win.mainloop()
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/06/09 09:00
回答1件
0
ベストアンサー
現物もマニュアルも手元にないので記憶だよりですが。
キーボードインタフェースでの入力なら、末尾に改行がついている(もしくは改行がつく設定ができる)はずです。(サフィックス設定)
entryに文字が入力されたら末尾の改行を検知して次のウィジットのフォーカスをセットすれば良いかと思います。
…ですが、tkinterには他の言語における、いわゆるOnChange
的なイベントがありません(少なくとも私の調べた限りでは)
なのでOnChange相当のイベントを自力で実装する必要があります。
で、ちょうど同じようにイベントを自力で実装したstackoverflowの記事がありましたので紹介します。
記事の内容はTextの拡張ですが、Entryにもほぼそのまま適用可能と思います。
https://stackoverflow.com/questions/40617515/python-tkinter-text-modified-callback
上記記事を参考にOnChange相当のイベントが発火するEntryクラスのサンプルを作ってみました。
(注:最低限の動きはしますが例外処理を非常にいい加減に実装しています。絶対にこのまま使用しないでください)
"\n"を検知していますが、サフィックス設定によっては\nにならないかもしれません。その辺はご自分で調査してください。
現物がないので末尾が改行のテキストデータをコピー&ペーストしてテストしています。バーコードリーダーでもおそらく同じ挙動のはずです。
python
1import tkinter as tk 2 3class SampleApp(tk.Tk): 4 5 def __init__(self, *args, **kwargs): 6 tk.Tk.__init__(self, *args, **kwargs) 7 8 e1 = CustomEntry(self) # CustomEntryにOnChange相当の機能を実装 9 e2 = CustomEntry(self) 10 e3 = CustomEntry(self) 11 12 e1.insert(0,"1") 13 e2.insert(0,"2") 14 e3.insert(0,"3") 15 16 e1.pack() 17 e2.pack() 18 e3.pack() 19 20 # イベントのバインド。TextModifiedという名称にしている(元記事と同じ) 21 e1.bind('<<TextModified>>',self.nextentry) 22 e2.bind('<<TextModified>>',self.nextentry) 23 e3.bind('<<TextModified>>',self.nextentry) 24 25 # 末尾が改行かどうかをチェック、改行だったらタブオーダーの次のウィジットへフォーカスを移す 26 def nextentry(self,event): 27 s = event.widget.get() 28 if len(s) == 0: 29 return 30 if event.widget.get()[-1] == "\n": 31 event.widget.tk_focusNext().focus_set() 32 33# OnChangeを実装したEntryクラス 34class CustomEntry(tk.Entry): 35 def __init__(self, *args, **kwargs): 36 """A Entry widget that report on internal widget commands""" 37 tk.Entry.__init__(self, *args, **kwargs) 38 39 # create a proxy for the underlying widget 40 self._orig = self._w + "_orig" 41 self.tk.call("rename", self._w, self._orig) 42 self.tk.createcommand(self._w, self._proxy) 43 44 # tkからコマンドが発行されるたびに呼び出される 45 def _proxy(self, command, *args): 46 cmd = (self._orig, command) + args 47 print(cmd) 48 # 発生理由のわからない例外が出てくるのでそういうのは全て握りつぶす 49 try: 50 result = self.tk.call(cmd) 51 except tk.TclError as ex: 52 return None 53 # 文字の変更に関するコマンドが発行された場合、TextModifiedイベントを発火させる 54 if command in ("insert", "delete", "replace"): 55 self.event_generate("<<TextModified>>") 56 return result 57 58 59if __name__ == "__main__": 60 app = SampleApp() 61 app.mainloop()
追記
コメントの内容を受けてtrace版を作ってみました。
新しいコンポーネントクラスは作らなくてもよくなります。
ただしbindのような柔軟なイベント処理ができない(trace発生元のStringVarはわかるがそこからバインドされているコンポーネントをたどるのは難しい)ので多数のコンポーネントが相手になるとソースがこんがらかりそうです。監視先が1つ2つだったら楽そうです。
python
1import tkinter as tk 2 3class SampleApp(tk.Tk): 4 5 def __init__(self, *args, **kwargs): 6 tk.Tk.__init__(self, *args, **kwargs) 7 # StringVarとEntryはコールバック内で参照するためインスタンス変数にする 8 self.sv1 = tk.StringVar() 9 self.sv1.trace("w",self.var_changed) # sv1に書き込みされるとvar_chagedがコールバック 10 11 self.e1 = tk.Entry(self, textvariable = self.sv1) # textvariableとsv1をバインド 12 e2 = tk.Entry(self) 13 14 e2.insert(0,"2") 15 16 self.e1.pack() 17 e2.pack() 18 # argsにはtrace発生元のVarの_nameが入っている 19 # StringVarはargsから探せるが発生元のエレメントを探すのは大変 20 # なのでイベント発生元はハードコーディング 21 def var_changed(self, *args): 22 s = self.sv1.get() 23 if len(s) == 0: 24 return 25 if s[-1] == "\n": 26 self.e1.tk_focusNext().focus_set() 27 28if __name__ == "__main__": 29 app = SampleApp() 30 app.mainloop()
投稿2020/06/10 10:20
編集2020/06/11 13:09総合スコア4447
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/06/11 12:09
2020/06/11 13:12
2020/06/11 13:41
2020/06/11 14:16
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。