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

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

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

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

Tkinter

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

Q&A

解決済

1回答

5854閲覧

Python3 Tkinter バーコードを使ってテキストボックスへ入力

person

総合スコア224

Python 3.x

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

Tkinter

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

0グッド

0クリップ

投稿2020/06/09 00:39

編集2020/06/09 01:48

複数のエントリ(テキストボックス)を配置するとき、バーコードリーダーでバーコードにある内容を入力したら自動で次のエントリにフォーカスが当たるようにしたいのですが下のソースコードで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ページで確認できます。

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

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

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

t_obara

2020/06/09 06:44

カッコ内の文の意図が読み取れません。一番困っている点は何ですか? バーコードリーダーで入力したことをどのように検知するかと言うことでしょうか。
person

2020/06/09 09:00

> バーコードリーダーで入力したことをどのように検知するかと言うことでしょうか。 そうです。可能であればその方法を知りたいです。
guest

回答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
hope_mucci

総合スコア4447

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

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

teamikl

2020/06/11 12:09

bind()で設定できるイベントはないのですよね。 バーコード側の設定は解りませんが、サフィックスを得られるなら StringVar の trace() メソッドでも、同様の変更通知を得られます。
hope_mucci

2020/06/11 13:12

StringVarとtraceの存在を初めて知りました(元のTkにはなかったような、tkinterにだけある?) trace版のコードも作ってみました。
teamikl

2020/06/11 13:41

説明補足ありがとうございます。イベント発生元は確かに解らなくなりますね 同じ状況で使うとしたら、同じくStringVarとEntryをセットにサブクラス化して TextModified イベントの実装に trace を使う等でしょうか。 ---- tcl の機能でした https://www.tcl.tk/man/tcl8.4/TclCmd/trace.htm trace - Monitor variable accesses。tkinterでの紹介が薄い部分ではあります。
hope_mucci

2020/06/11 14:16

なるほど、Tclの機能でしたか。Tkのほうばっか見てました。。。 同じサブクラス化するにしてもtrace型のほうが変なフックをかけなくてもよくなるので見通しは良くなるかな?と考えます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問