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

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

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

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

Python

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

Q&A

解決済

1回答

2529閲覧

Python(TkInter)  【ScrolledTextに一度フォーカスがあたると、タブキーで次のWidgetにフォーカスが移らない】

saya24

総合スコア247

Tkinter

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

Python

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

0グッド

0クリップ

投稿2020/05/18 05:08

標題の件、ありがちな質問かもしれませんがよろしくお願いします。各Widgetには takefocus=1 のフォーカス遷移対象の設定を行っています。

つまりは ScrolledTextの中では タブが 別の機能(インデント飛ばし)として働いてしまうがゆえのことと思われます。

尚、下記コードでは
・コンボボックスからなんらかのアイテムが選択されている
・ScrolledTextに何らかの文字が入力されている
双方の条件が整わない限り 配置のボタンは 有効(status='normal')にならないようにしているつもりです。

(ScrolledTextからフォーカスが抜けたら、という手続きを 現在は イベントのバインドに<Leave>を設定して対応しています。
タブキーがうまく作用しない関係で、現在はマウスのカーソルが当該Widgetから外れた場合だけ ScrolledTextの入力枠チェックが働いている状態です)  
よろしくお願いします。

Python

1from tkinter import * 2import tkinter.ttk as ttk 3import tkinter.scrolledtext as tksc 4import math 5 6 7 8class Apprication(ttk.Frame): 9 10 def __init__(self, app): 11 super().__init__(app) 12 self.pack() 13 14 btn = ttk.Button(self, text="Sub", command=self.openDialog) 15 btn.grid(row=1, column=0) 16 17 18 19 # 子画面開く 20 def openDialog(self): 21 22 self.dialog = Toplevel(self) 23 self.dialog.title("Sub Menu") 24 25 #フォームサイズを実行端末から導き、ド真中に配置表示 26 lw = math.ceil(ww * 0.408) 27 lh = math.ceil(wh * 0.477) 28 self.dialog.geometry(str(lw)+"x"+str(lh)+"+"+str(int(ww/2-lw/2))+"+"+str(int(wh/2-lh/2)) ) 29 30 self.dialog.configure(bg="#F0FFFF") 31 self.dialog.resizable(0,0) 32 self.dialog.protocol('WM_DELETE_WINDOW', (lambda: 'pass')()) 33 34 # 当該ダイアログのカーソルを変更し、関数側でもカーソルを変更できるように 35 self.dialog['cursor'] = 'hand2' 36 self.this = self.dialog 37 38 # modalに 39 self.dialog.grab_set() 40 41 42 43 # コンボボックス 44 db = {1:"AAA",2:"BBB",3:"CCC"} 45 self.v1 = StringVar() 46 cmbox1 = ttk.Combobox(self.dialog, takefocus=1, width=5, justify=CENTER, values=list(db.keys()), state='readonly', textvariable=self.v1) 47 cmbox1.bind('<<ComboboxSelected>>', self.cmbox1_selected) 48 cmbox1.grid(row=0, column=0, padx=(10, 0), pady=(10,0), sticky=W+E) 49 cmbox1.focus_set() 50 51 52 # テキストボックス 53 self.txt1 = Entry(self.dialog, state="readonly", takefocus=1) 54 self.txt1.grid(row=0, column=1, columnspan=7, sticky=W+E, pady=(10,0)) 55 56 57 # ★入力枠★ 58 self.scrtxt1 = tksc.ScrolledText(self.dialog, bg="black", fg="orange", font=("Helvetica",11), insertbackground="orange", blockcursor=True, height=6, state="disable", takefocus=1) 59 self.scrtxt1.bind("<Leave>", self.scrtxt1_Chk) 60 self.scrtxt1.grid(row=2, column=0, columnspan=11, sticky=W+E, padx=10) 61 62 63 # 実行ボタン 64 self.btn1 = Button(self.dialog, text='Execute', width=10, state=DISABLED, takefocus=1) 65 self.btn1.grid(row=3, columnspan=11, pady=(0, 20), sticky=N) 66 67 68 # 閉じるボタン 69 btn3 = Button(self.dialog, text='Quit', command=self.closeDialog, width=10, takefocus=1) 70 btn3.grid(row=5, column=10, pady=10, padx=(0,10)) 71 72 73 self.dialog.grid_rowconfigure(1, weight=1) 74 self.dialog.grid_rowconfigure(3, weight=1) 75 self.dialog.grid_columnconfigure(2, weight=1) 76 77 78 79 80 # 子画面閉じる 81 def closeDialog(self): 82 self.dialog.destroy() 83 84 85 # コンボボックス選択値をテキストボックス表示 86 def cmbox1_selected(self, event): 87 self.txt1['state'] = 'normal' 88 self.txt1.delete(0, END) 89 self.txt1.insert(END, self.v1.get()) 90 self.txt1['state'] = 'readonly' 91 92 self.scrtxt1['state'] = 'normal' 93 self.btn1_Enable() 94 95 96 # ★★★入力枠チェック★★★ 97 def scrtxt1_Chk(self, event): 98 self.btn1_Enable() 99 100 101 # 実行ボタンの有効化 102 def btn1_Enable(self): 103 if (self.scrtxt1.get('1.0', 'end -1c') != ""): 104 self.btn1['state'] = 'normal' 105 else: 106 self.btn1['state'] = 'disable' 107 108 109if __name__ == '__main__': 110 111 #世間でいうrootをappとしています 112 app = Tk() 113 114 #実行端末の画面サイズを取得 115 ww = app.winfo_screenwidth() 116 wh = app.winfo_screenheight() 117 118 app.update_idletasks() 119 120 #フォームサイズを実行端末から導き、ド真中に配置表示 121 lw = math.ceil(ww * 0.208) 122 lh = math.ceil(wh * 0.277) 123 app.geometry(str(lw)+"x"+str(lh)+"+"+str(int(ww/2-lw/2))+"+"+str(int(wh/2-lh/2)) ) 124 125 #タイトルを指定 126 app.title("Main Menu") 127 128 #フォームの最大化、×ボタン操作を無効化 129 app.resizable(0,0) 130 #app.protocol('WM_DELETE_WINDOW', (lambda: 'pass')()) 131 132 # カーソル変更 133 app["cursor"] = "hand2" 134 135 app.configure(bg="#F0FFFF") 136 137 # フレームを作成する 138 frame = Apprication(app) 139 # 格納したTkインスタンスのmainloopで画面を起こす 140 app.mainloop()

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

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

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

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

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

guest

回答1

0

ベストアンサー

下記のリンクに同様の質問がありました。
こちらの1つ目の回答の方法で良いかと思います。

https://stackoverflow.com/questions/1450180/change-the-focus-from-one-text-widget-to-another

Python

1from tkinter import * 2import tkinter.ttk as ttk 3import tkinter.scrolledtext as tksc 4import math 5 6class Apprication(ttk.Frame): 7 8 def __init__(self, app): 9 super().__init__(app) 10 self.pack() 11 12 btn = ttk.Button(self, text="Sub", command=self.openDialog) 13 btn.grid(row=1, column=0) 14 15 def focus_next_window(self, event): 16 event.widget.tk_focusNext().focus() 17 return "break" 18 19 # 子画面開く 20 def openDialog(self): 21 22 self.dialog = Toplevel(self) 23 self.dialog.title("Sub Menu") 24 25 #フォームサイズを実行端末から導き、ド真中に配置表示 26 lw = math.ceil(ww * 0.408) 27 lh = math.ceil(wh * 0.477) 28 self.dialog.geometry(str(lw)+"x"+str(lh)+"+"+str(int(ww/2-lw/2))+"+"+str(int(wh/2-lh/2)) ) 29 30 self.dialog.configure(bg="#F0FFFF") 31 self.dialog.resizable(0,0) 32 self.dialog.protocol('WM_DELETE_WINDOW', (lambda: 'pass')()) 33 34 # 当該ダイアログのカーソルを変更し、関数側でもカーソルを変更できるように 35 self.dialog['cursor'] = 'hand2' 36 self.this = self.dialog 37 38 # modalに 39 self.dialog.grab_set() 40 41 # コンボボックス 42 db = {1:"AAA",2:"BBB",3:"CCC"} 43 self.v1 = StringVar() 44 cmbox1 = ttk.Combobox(self.dialog, takefocus=1, width=5, justify=CENTER, values=list(db.keys()), state='readonly', textvariable=self.v1) 45 cmbox1.bind('<<ComboboxSelected>>', self.cmbox1_selected) 46 cmbox1.grid(row=0, column=0, padx=(10, 0), pady=(10,0), sticky=W+E) 47 cmbox1.focus_set() 48 49 50 # テキストボックス 51 self.txt1 = Entry(self.dialog, state="readonly", takefocus=1) 52 self.txt1.grid(row=0, column=1, columnspan=7, sticky=W+E, pady=(10,0)) 53 54 55 # ★入力枠★ 56 self.scrtxt1 = tksc.ScrolledText(self.dialog, bg="black", fg="orange", font=("Helvetica",11), insertbackground="orange", blockcursor=True, height=6, state="disable", takefocus=1) 57 self.scrtxt1.bind("<Leave>", self.scrtxt1_Chk) 58 self.scrtxt1.grid(row=2, column=0, columnspan=11, sticky=W+E, padx=10) 59 self.scrtxt1.bind("<Tab>", self.focus_next_window) 60 61 # 実行ボタン 62 self.btn1 = Button(self.dialog, text='Execute', width=10, state=DISABLED, takefocus=1) 63 self.btn1.grid(row=3, columnspan=11, pady=(0, 20), sticky=N) 64 65 66 # 閉じるボタン 67 btn3 = Button(self.dialog, text='Quit', command=self.closeDialog, width=10, takefocus=1) 68 btn3.grid(row=5, column=10, pady=10, padx=(0,10)) 69 70 71 self.dialog.grid_rowconfigure(1, weight=1) 72 self.dialog.grid_rowconfigure(3, weight=1) 73 self.dialog.grid_columnconfigure(2, weight=1) 74 75 76 77 78 # 子画面閉じる 79 def closeDialog(self): 80 self.dialog.destroy() 81 82 83 # コンボボックス選択値をテキストボックス表示 84 def cmbox1_selected(self, event): 85 self.txt1['state'] = 'normal' 86 self.txt1.delete(0, END) 87 self.txt1.insert(END, self.v1.get()) 88 self.txt1['state'] = 'readonly' 89 90 self.scrtxt1['state'] = 'normal' 91 self.btn1_Enable() 92 93 94 # ★★★入力枠チェック★★★ 95 def scrtxt1_Chk(self, event): 96 self.btn1_Enable() 97 98 99 # 実行ボタンの有効化 100 def btn1_Enable(self): 101 if (self.scrtxt1.get('1.0', 'end -1c') != ""): 102 self.btn1['state'] = 'normal' 103 else: 104 self.btn1['state'] = 'disable' 105 106 107if __name__ == '__main__': 108 109 #世間でいうrootをappとしています 110 app = Tk() 111 112 #実行端末の画面サイズを取得 113 ww = app.winfo_screenwidth() 114 wh = app.winfo_screenheight() 115 116 app.update_idletasks() 117 118 #フォームサイズを実行端末から導き、ド真中に配置表示 119 lw = math.ceil(ww * 0.208) 120 lh = math.ceil(wh * 0.277) 121 app.geometry(str(lw)+"x"+str(lh)+"+"+str(int(ww/2-lw/2))+"+"+str(int(wh/2-lh/2)) ) 122 123 #タイトルを指定 124 app.title("Main Menu") 125 126 #フォームの最大化、×ボタン操作を無効化 127 app.resizable(0,0) 128 #app.protocol('WM_DELETE_WINDOW', (lambda: 'pass')()) 129 130 # カーソル変更 131 app["cursor"] = "hand2" 132 133 app.configure(bg="#F0FFFF") 134 135 # フレームを作成する 136 frame = Apprication(app) 137 # 格納したTkインスタンスのmainloopで画面を起こす 138 app.mainloop()

投稿2020/05/18 05:32

編集2020/05/18 05:34
magichan

総合スコア15898

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

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

saya24

2020/05/18 06:08

いつもありがとうございます、非常に助かりました。 無事タブキーでScrolledTextから 次のWidgetへフォーカスが移ってくれました。 すみません、差し支えなければ教えてください。 当該Widgetからフォーカスが抜けたにも関わらず、<Leave>のイベント察知で仕掛けている関数scrtxt1_Chkが動作してくれないようです。Leaveじゃダメなのでしょうか? Leaveとはマウスカーソルが外れた場合のみなのでしょうか....フォーカスが外れた場合のイベントの記載がこちらになく<http://bacspot.dip.jp/virtual_link/www/si.musashi-tech.ac.jp/new_www/Python_IntroTkinter/02/index-2.html>
magichan

2020/05/18 06:39 編集

1つ前の質問の回答で挙げたリンク先を見て下さい。 <Leave> はマウスポインタがWidgetから離れた際に発火するイベントです。 フォーカスが外れたときは、<FocusOut> イベントをお使いください。
saya24

2020/05/18 06:52

何から何までありがとうございます、magichanさんに頭があがりません!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問