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

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

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

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

Python

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

Q&A

解決済

1回答

1275閲覧

TkInter: 共通の関数を利用して Entryウィジェット(テキストボックス)の設定先を可変させたい。呼び出しウィジェットの認識方法を再確認したい

saya24

総合スコア227

Tkinter

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

Python

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

0グッド

0クリップ

投稿2021/10/17 10:54

編集2021/10/18 06:41

大変初歩的なことをお聞きして申し訳ないです。
標題の内容を達成するため、関数内のコードを以下のようにしています。 一応に目的は達成され 設定先のEntryウィジェットを 押下されたButtonウィジェットのキャプション(表示内容=event.widget["text"])から判断している状況です。もう一歩改良できないか?と 質問を掲載させて頂きました。

python

1 def open_FileDialog(event): 2 file = filedialog.askopenfilename() #パス取得 3 if event.widget["text"] == "入力ファイル指定": 4 ent_InputPath.configure(state='normal') 5 ent_InputPath.delete(0, tk.END) 6 ent_InputPath.insert(tk.END, str(file)) 7 ent_InputPath.configure(state='disabled') 8 else: 9 ent_OutputPath.configure(state='normal') 10 ent_OutputPath.delete(0, tk.END) 11 ent_OutputPath.insert(tk.END, str(file)) 12 ent_OutputPath.configure(state='disabled')

イメージ説明イメージ説明

質問①
この方法しかないのなら やむを得ないのですが、フレーム上のEntryウィジェットのインデックス番号などで判断できないものでしょうか?

質問②
全く別件で申し訳ないですが ついでに....
Buttonウィジェットを一度選択すると、押下され続けている雰囲気のイメージになってしまいます。これは 何が原因と考えられるでしょうか?

以下、コードの全容です。上記画像のフォームは 起動後に立上がるメニューフォームで、一番上のボタン押下から現れます。
Pythonの環境さえ あれば お試しいただける内容と思います。

python

1# tkinterのインポート 2import tkinter as tk 3import tkinter.ttk as ttk 4import math 5import os 6from tkinter import filedialog 7################################################################################# 8# # 9# 画面生成 # 10# # 11# # 12################################################################################# 13def resource_path(relative_path): 14 try: 15 # PyInstaller creates a temp folder and stores path in _MEIPASS 16 base_path = sys._MEIPASS 17 except Exception: 18 base_path = os.path.abspath(".") 19 20 return os.path.join(base_path, relative_path) 21 22 23def adjust_windowsize(root): 24 ww = root.winfo_screenwidth() 25 wh = root.winfo_screenheight() 26 27 lw = math.ceil(ww * 0.208) 28 lh = math.ceil(wh * 0.277) 29 30 root.geometry(str(lw)+"x"+str(lh)+"+"+str(int(ww/2-lw/2))+"+"+str(int(wh/2-lh/2))) 31 32################################################################################# 33# # 34# フレーム生成 # 35# # 36# # 37################################################################################# 38def generate_frame(root): 39 40 def change_frame(frame): 41 frame.tkraise() 42 43 def open_FileDialog(event): 44 file = filedialog.askopenfilename() #パス取得 45 if event.widget["text"] == "入力ファイル指定": 46 ent_InputPath.configure(state='normal') 47 ent_InputPath.delete(0, tk.END) 48 ent_InputPath.insert(tk.END, str(file)) 49 ent_InputPath.configure(state='disabled') 50 else: 51 ent_OutputPath.configure(state='normal') 52 ent_OutputPath.delete(0, tk.END) 53 ent_OutputPath.insert(tk.END, str(file)) 54 ent_OutputPath.configure(state='disabled') 55 56 57 # メインメニュー用フレーム設置 58 frmMain = ttk.Frame(root) 59 frmMain.grid(row=0, column=0, sticky=tk.E + tk.W + tk.N + tk.S) 60 61 # メインメニューにボタン配置 62 btn_SettingMenu = tk.Button(frmMain, text = "入出力定義", font=("",0,"normal","roman","normal"), command=lambda: change_frame(frmIOMenu)) 63 btn_SettingMenu.pack(fill = tk.BOTH, expand=True) 64 65 btn_SettingMenu = tk.Button(frmMain, text = "変換定義", font=("",0,"normal","roman","normal")) 66 btn_SettingMenu.pack(fill = tk.BOTH, expand=True) 67 68 btn_RunMenu = tk.Button(frmMain, text = "実行メニュー", font=("",0,"normal","roman","normal")) 69 btn_RunMenu.pack(fill = tk.BOTH, expand=True) 70 btn_RunMenu.focus_set() 71 72 btn_SettingMenu = tk.Button(frmMain, text = "終了", font=("",0,"normal","roman","normal"), command=root.destroy) 73 btn_SettingMenu.pack(fill = tk.BOTH, expand=True) 74 75 76 77 # 入出力定義メニュー用フレーム設置 78 frmIOMenu = ttk.Frame(root) 79 frmIOMenu.grid(row=0, column=0, sticky=tk.E + tk.W + tk.N + tk.S) 80 81 82 # 入力ファイル指定ボタン、選択ファイル格納テキストボックス配置 83 btn_AssignInputFile = tk.Button(frmIOMenu, text = "入力ファイル指定") 84 btn_AssignInputFile.bind("<Button>", open_FileDialog) #問題の関数を呼出し 85 btn_AssignInputFile.grid(row=0, column=0, sticky=tk.E + tk.W + tk.N + tk.S) 86 87 ent_InputPath = tk.Entry(frmIOMenu, state="disabled") 88 ent_InputPath.grid(row=0, column=1, columnspan=9, sticky=tk.E + tk.W + tk.N + tk.S) 89 90 91 # 出力ファイル指定ボタン、選択ファイル格納テキストボックス配置 92 btn_AssignOutFile = tk.Button(frmIOMenu, text = "出力ファイル指定") 93 btn_AssignOutFile.bind("<Button>", open_FileDialog) #問題の関数を呼出し 94 btn_AssignOutFile.grid(row=1, column=0, sticky=tk.E + tk.W + tk.N + tk.S) 95 96 ent_OutputPath = tk.Entry(frmIOMenu, state="disabled") 97 ent_OutputPath.grid(row=1, column=1, columnspan=9, sticky=tk.E + tk.W + tk.N + tk.S) 98 99 btn_ReturnMenu = tk.Button(frmIOMenu, text = "メニューへ戻る", command=lambda: change_frame(frmMain)) 100 btn_ReturnMenu.grid(row=2, column=8, sticky=tk.E + tk.W + tk.N + tk.S) 101 102 # 起動時メインのフレームを前面に 103 frmMain.tkraise() 104 105 106 107 108if __name__ == "__main__": 109 # ウインドウの作成 110 root = tk.Tk() 111 112 #フォームサイズを実行端末から導き、ド真中に配置表示 113 adjust_windowsize(root) 114 115 #タイトルを指定 116 root.title("TkInterの勉強") 117 118 #フレーム切替え達成の上で とても重要、ルートのグリッド定義 119 root.grid_rowconfigure(0, weight=1) 120 root.grid_columnconfigure(0, weight=1) 121 122 #タイトル左隅のアイコン 123 #iconfile = resource_path("images\favicon.ico") 124 #root.iconbitmap(default=iconfile) 125 126 #フォームの最大化、×ボタン操作を無効化 127 root.resizable(0,0) 128 root.protocol('WM_DELETE_WINDOW', (lambda: 'pass')()) 129 130 # カーソル変更 131 root["cursor"] = "hand2" 132 133 generate_frame(root) 134 135 root.mainloop()

20211018 1540 追記

python

1#関数 2 def open_FileDialog(ent, btn): 3 def error_handler(): 4 error_message(msg001) 5 ent.configure(state='normal') 6 ent.delete(0, tk.END) 7 ent.configure(state='disabled') 8 9 file = filedialog.askopenfilename() #パス取得 10 11 if btn == 0: 12 if file == ent_OutputPath.get(): #入力と出力で同じファイル指定を受付けないように 13 btn_AssignInputFile.focus_set() 14 error_handler() 15 return 16 else: 17 if file == ent_InputPath.get(): #入力と出力で同じファイル指定を受付けないように 18 btn_AssignOutputFile.focus_set() 19 error_handler() 20 return 21 22 ent.configure(state='normal') 23 ent.delete(0, tk.END) 24 ent.insert(tk.END, file) 25 ent.configure(state='disabled') 26 btn_ReturnMenu.focus_set()

python

1# 入力ファイル指定ボタン、選択ファイル格納テキストボックス配置 2 ent_InputPath = tk.Entry(frmIOMenu, state="disabled") 3 ent_InputPath.grid(row=0, column=1, columnspan=9, sticky=tk.E + tk.W + tk.N + tk.S) 4 5 btn_AssignInputFile = tk.Button(frmIOMenu, text = "入力ファイル指定", command=lambda : open_FileDialog(ent_InputPath, 0)) 6 btn_AssignInputFile.grid(row=0, column=0, sticky=tk.E + tk.W + tk.N + tk.S) 7 8 # 出力ファイル指定ボタン、選択ファイル格納テキストボックス配置 9 ent_OutputPath = tk.Entry(frmIOMenu, state="disabled") 10 ent_OutputPath.grid(row=1, column=1, columnspan=9, sticky=tk.E + tk.W + tk.N + tk.S) 11 12 btn_AssignOutputFile = tk.Button(frmIOMenu, text = "出力ファイル指定", command=lambda : open_FileDialog(ent_OutputPath, 1)) 13 btn_AssignOutputFile.grid(row=1, column=0, sticky=tk.E + tk.W + tk.N + tk.S)

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

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

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

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

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

guest

回答1

0

ベストアンサー

質問①

open_FileDialogの中で分岐しているのがなんか気持ち悪いってことでしょうか。
ボタンのコマンド関数指定においてラムダ式で対象Entryを指定してあげればイベント処理時に分岐しなくすることはできます。
修正例は質問②と合わせて後述します。

質問②

ボタン押下時処理の指定をbindを使って指定しているためだと思います。
この処理をフックしたせいで元のスタイルに戻す処理が行われていないのでしょう。
ボタン押下時処理はボタン生成時にcommandで指定できます。

まとめると

Python

1# tkinterのインポート 2import tkinter as tk 3import tkinter.ttk as ttk 4import math 5import os 6from tkinter import filedialog 7################################################################################# 8# # 9# 画面生成 # 10# # 11# # 12################################################################################# 13def resource_path(relative_path): 14 try: 15 # PyInstaller creates a temp folder and stores path in _MEIPASS 16 base_path = sys._MEIPASS 17 except Exception: 18 base_path = os.path.abspath(".") 19 20 return os.path.join(base_path, relative_path) 21 22 23def adjust_windowsize(root): 24 ww = root.winfo_screenwidth() 25 wh = root.winfo_screenheight() 26 27 lw = math.ceil(ww * 0.208) 28 lh = math.ceil(wh * 0.277) 29 30 root.geometry(str(lw)+"x"+str(lh)+"+"+str(int(ww/2-lw/2))+"+"+str(int(wh/2-lh/2))) 31 32################################################################################# 33# # 34# フレーム生成 # 35# # 36# # 37################################################################################# 38def generate_frame(root): 39 40 def change_frame(frame): 41 frame.tkraise() 42 43 def open_FileDialog(ent): 44 file = filedialog.askopenfilename() #パス取得 45 ent.configure(state='normal') 46 ent.delete(0, tk.END) 47 ent.insert(tk.END, str(file)) 48 ent.configure(state='disabled') 49 50 51 # メインメニュー用フレーム設置 52 frmMain = ttk.Frame(root) 53 frmMain.grid(row=0, column=0, sticky=tk.E + tk.W + tk.N + tk.S) 54 55 # メインメニューにボタン配置 56 btn_SettingMenu = tk.Button(frmMain, text = "入出力定義", font=("",0,"normal","roman","normal"), command=lambda: change_frame(frmIOMenu)) 57 btn_SettingMenu.pack(fill = tk.BOTH, expand=True) 58 59 btn_SettingMenu = tk.Button(frmMain, text = "変換定義", font=("",0,"normal","roman","normal")) 60 btn_SettingMenu.pack(fill = tk.BOTH, expand=True) 61 62 btn_RunMenu = tk.Button(frmMain, text = "実行メニュー", font=("",0,"normal","roman","normal")) 63 btn_RunMenu.pack(fill = tk.BOTH, expand=True) 64 btn_RunMenu.focus_set() 65 66 btn_SettingMenu = tk.Button(frmMain, text = "終了", font=("",0,"normal","roman","normal"), command=root.destroy) 67 btn_SettingMenu.pack(fill = tk.BOTH, expand=True) 68 69 70 71 # 入出力定義メニュー用フレーム設置 72 frmIOMenu = ttk.Frame(root) 73 frmIOMenu.grid(row=0, column=0, sticky=tk.E + tk.W + tk.N + tk.S) 74 75 # 入力ファイル指定ボタン、選択ファイル格納テキストボックス配置 76 ent_InputPath = tk.Entry(frmIOMenu, state="disabled") 77 ent_InputPath.grid(row=0, column=1, columnspan=9, sticky=tk.E + tk.W + tk.N + tk.S) 78 79 btn_AssignInputFile = tk.Button(frmIOMenu, text = "入力ファイル指定", command=lambda : open_FileDialog(ent_InputPath)) 80 btn_AssignInputFile.grid(row=0, column=0, sticky=tk.E + tk.W + tk.N + tk.S) 81 82 # 出力ファイル指定ボタン、選択ファイル格納テキストボックス配置 83 ent_OutputPath = tk.Entry(frmIOMenu, state="disabled") 84 ent_OutputPath.grid(row=1, column=1, columnspan=9, sticky=tk.E + tk.W + tk.N + tk.S) 85 86 btn_AssignOutFile = tk.Button(frmIOMenu, text = "出力ファイル指定", command=lambda : open_FileDialog(ent_OutputPath)) 87 btn_AssignOutFile.grid(row=1, column=0, sticky=tk.E + tk.W + tk.N + tk.S) 88 89 btn_ReturnMenu = tk.Button(frmIOMenu, text = "メニューへ戻る", command=lambda: change_frame(frmMain)) 90 btn_ReturnMenu.grid(row=2, column=8, sticky=tk.E + tk.W + tk.N + tk.S) 91 92 # 起動時メインのフレームを前面に 93 frmMain.tkraise() 94 95 96 97 98if __name__ == "__main__": 99 # ウインドウの作成 100 root = tk.Tk() 101 102 #フォームサイズを実行端末から導き、ド真中に配置表示 103 adjust_windowsize(root) 104 105 #タイトルを指定 106 root.title("TkInterの勉強") 107 108 #フレーム切替え達成の上で とても重要、ルートのグリッド定義 109 root.grid_rowconfigure(0, weight=1) 110 root.grid_columnconfigure(0, weight=1) 111 112 #タイトル左隅のアイコン 113 #iconfile = resource_path("images\favicon.ico") 114 #root.iconbitmap(default=iconfile) 115 116 #フォームの最大化、×ボタン操作を無効化 117 root.resizable(0,0) 118 root.protocol('WM_DELETE_WINDOW', (lambda: 'pass')()) 119 120 # カーソル変更 121 root["cursor"] = "hand2" 122 123 generate_frame(root) 124 125 root.mainloop()

投稿2021/10/17 23:34

nomuken

総合スコア1627

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

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

saya24

2021/10/18 01:06

できました、ありがとうございます。 前回のPythonの勉強から だいぶ時間があいてしまい 一からやりなおしの雰囲気ですが まずはラムダ式の復讐から始めます。 親切丁寧なご回答 重ねてお礼を申し上げます。
saya24

2021/10/18 02:38

確かに 関数の引数に設定先のEntryウィジェットを指定することで 値格納を発火元ウィジェットを意識することなく 達成することができたのですが、 例えば 関数内でエラーを起こした際(入力ファイルと出力ファイルに、同じ指定を行われたケースなど)、メッセージ出力後、発火元のコマンドボタンに フォーカスをあてたい ことに気がつきました。 やはり、発火元のウィジェットも、引数にあたえる必要があるとなると どういう対策をとれば良いでしょうか? 差し支えなければ教えてください。
nomuken

2021/10/18 03:15

問題②がありますのでbindを使わずに修正する必要がありますね。 やりたいことによって一つの関数でやりきるのは限界があるかもしれません。 現在上がっているのだと > 入力ファイルと出力ファイルに、同じ指定を行われたケース 他方のEntryをラムダ式の引数に加えてそれと同一チェックをする。 > 発火元のコマンドボタンに フォーカスをあてたい フォーカスを与えたいボタンをラムダ式の引数に加える・・・と言いたいところですがボタン生成はラムダ式指定の後なのでできません。各種ウィジットの指定はあきらめ、識別子だけを与えます(入力ファイルは0、出力ファイルは1など)あとはopen_FileDialog関数の冒頭で識別子に応じて対象ウィジットを選択し、処理します。
saya24

2021/10/18 06:37

nomukenさん 引き続きのご見解ありがとうございます。 open_FileDialogの関数と当該呼出し元を編集して、なんとかエラー時のボタンへのフォーカス 及び、選択ファイルのパスが目的のテキストボックスに収まるようになりました。(すぐ現況の関係部分のコードを 本文に追加します) リターンキーの押下でも 同じ操作をするようにしたいのですが、以外にこれが難題なのですね~ だんだんと細かい使い勝手のにまで視野がいってしまい.... バインドさせるためには クラス化とか 結構大がかりな改修になるかなぁ.... 同じ掲載でやりとりを継続してしまい 申し訳ないです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問