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

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

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

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

Q&A

解決済

2回答

1277閲覧

TkeasyGUIのCalendarButtonのカレンダーポップアップの閉じるボタンを無効化したい

hy-0820

総合スコア1

Python

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

1グッド

0クリップ

投稿2024/09/13 05:39

実現したいこと

TkeasyGUIでCalendarButtonを設定し、出てくるカレンダーポップアップの閉じるボタン(×ボタン)を無効化したい。

前提

TkeasyGUIでCalendarButtonを設置。
アプリを起動させウィンドウが出てきてから、CalendarButtonを押下するとカレンダーポップアップが出てくる。
カレンダーポップ上で日付を選択せず、右上の閉じるボタン(×ボタン)を押すと、カレンダーポップアップは閉じられ元のウィンドウに戻るが、その後どのボタンを押しても反応しなくなります。
どのようなコードを書けば、閉じるボタンを押した後に元のウィンドウが操作できるようになるか知りたいです。
もしくは、カレンダーポップアップの閉じるボタンを触れなくするように、無効化できるのであれば、それでも問題ないと思っています。

発生している問題・エラーメッセージ

①アプリを起動させ、設定したカレンダーボタンを押す
イメージ説明

②カレンダーポップアップが出てくるので、閉じるボタンで閉じる
イメージ説明

③カレンダーポップアップは閉じられるが、元のウィンドウが反応しなくなる。
イメージ説明

該当のソースコード

Python

1import TkEasyGUI as eg 2 3layout = [ 4 [eg.Text("   設定期間      : ", font = ('Meiryo',10),)], 5 [eg.InputText(key = "start_date" , font = ('Meiryo',10), size=(13,1) ,readonly = True)], 6 [eg.CalendarButton("開始日", font = ('Meiryo',8), key = "start_btn")], 7 [eg.Text(" ~ ",font = ('Meiryo',10))], 8 [eg.InputText(key = "end_date" , font = ('Meiryo',10), size=(13,1) ,readonly = True)], 9 [eg.CalendarButton("終了日", font = ('Meiryo',8), key = "end_btn")], 10 [eg.Text("            ", font = ('Meiryo',10))]] 11 12window = eg.Window("日付",layout) 13 14while True: 15 event,values = window.read() 16 if event == eg.WINDOW_CLOSED: 17 break 18 19 20window.close() 21

試したこと

teratailやGoogle等で検索した
ソースコードを自分なりに変更した

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

なし

melian👍を押しています

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

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

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

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

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

guest

回答2

0

ベストアンサー

ソースコードを確認してみると、grab_set() でモーダルウィンドウにしています。

tkeasygui-python/TkEasyGUI/widgets.py at main · kujirahand/tkeasygui-python

python

1 if modal: 2 # set modal action 3 self.window.attributes("-topmost", 1) # topmost 4 # self.window.transient(parent) 5 self.window.grab_set() 6 self.window.focus_force()

ですが、ウィンドウのクローズボタンをクリックする際に実行される _close_handler() メソッドではモーダル状態を解除していません。

tkeasygui-python/TkEasyGUI/widgets.py at main · kujirahand/tkeasygui-python

python

1 # set window properties 2 self.set_title(title) 3 self.window.protocol("WM_DELETE_WINDOW", lambda : self._close_handler())

tkeasygui-python/TkEasyGUI/widgets.py at main · kujirahand/tkeasygui-python

python

1 def _close_handler(self): 2 """Handle a window close event.""" 3 self.flag_alive = False 4 if self.timeout_id is not None: 5 self.window.after_cancel(self.timeout_id) 6 self._event_handler(WINDOW_CLOSED, None)

ここで self.window.grab_release() を追加すると、問題が解消します。

python

1 def _close_handler(self): 2 """Handle a window close event.""" 3 # 追加 4 if self.modal: 5 self.window.grab_release() 6 self.flag_alive = False 7 if self.timeout_id is not None: 8 self.window.after_cancel(self.timeout_id) 9 self._event_handler(WINDOW_CLOSED, None)

投稿2024/09/13 12:57

編集2024/09/13 13:02
melian

総合スコア21106

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

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

hy-0820

2024/09/17 00:54

melianさん 回答ありがとうございます!解決できました!Python初学者で色々勉強中ですがmelianさんのようになれるよう精進します。本当に助かりました!
guest

0

TkEasyGUIの不具合のような感じがするので、(実際不具合かどうかはおいといて)GitHubのissuesで尋ねた方がいい気がします。
https://github.com/kujirahand/tkeasygui-python/issues


ちょっと見てみました。

以下の最小コードでも発生しますね。

python

1import TkEasyGUI as eg 2 3layout = [ 4 [eg.Button('Hoge')], 5 [eg.Button('Piyo')], 6] 7 8with eg.Window('Hello', layout) as window: 9 for event, values in window.event_iter(): 10 if event == 'Hoge': 11 eg.dialogs.popup_buttons('Hello') 12 elif event == 'Piyo': 13 eg.dialogs.popup_get_date('Hello') 14

ソースコードも見てみました。
以下は、 TkEasyGUI/widgets.py の中から抜粋です。

python

1class Window: 2 def __init__( 3 self, 4 title: str, 5 layout: list[list[Element]], # set elements layout 6 size: Union[tuple[str, int], None] = None, # window size 7 resizable: bool = False, 8 font: Union[FontType, None] = None, 9 modal: bool = False, # modal window 10 keep_on_top: bool = False, # keep on top 11 no_titlebar: bool = False, # hide titlebar 12 grab_anywhere: bool = False, # can move window by dragging anywhere 13 alpha_channel: float = 1.0, # window alpha channel 14 enable_key_events: bool = False, # enable keyboard events 15 return_keyboard_events: bool = False, # enable keyboard events (for compatibility) 16 location: Union[tuple[int, int], None] = None, # window location 17 center_window: bool = True, # move window to center 18 row_padding: int = 2, # row padding 19 padding_x: int = 8, # x padding around the window 20 padding_y: int = 8, # y padding around the window 21 icon: Union[str, None] = None, # window icon, specify filename (Experimental) 22 show_scrollbar: bool = False, # show scrollbar (Experimental) 23 **kw, 24 ) -> None: 25 # 省略 26 self.window.protocol("WM_DELETE_WINDOW", lambda : self._close_handler()) 27 # 省略 28 29 def _close_handler(self): 30 """Handle a window close event.""" 31 self.flag_alive = False 32 if self.timeout_id is not None: 33 self.window.after_cancel(self.timeout_id) 34 self._event_handler(WINDOW_CLOSED, None) 35 36 def close(self) -> None: 37 """Close the window.""" 38 # The phenomenon where a closed window remains visible is occurring, so forcibly making it transparent. 39 try: 40 self.set_alpha_channel(0.0) # force hide 41 except Exception as _: 42 pass 43 try: 44 self.hide() 45 except Exception as _: 46 pass 47 # already closed? 48 if not self.flag_alive: 49 return 50 # close window 51 try: 52 self.flag_alive = False 53 _window_pop(self) 54 self.window.destroy() # close window 55 win_count = _window_count() 56 if win_count == 0: 57 self.window.quit() # quit app 58 except Exception as e: 59 print(f"Window.close.failed: {e}", file=sys.stderr) 60 pass 61

ざっと見たところ、ウィンドウクローズイベントで flag_aliveFalse にして、その場合には close メソッドの中で一部処理を省いているようです。

ただ、自分もTkinterはよく知らないのですが、ググってみると、

上記のサイトなど参考にすると、

例えば終了ボタンでウィンドウが閉じられる場合は、WM_DELETE_WINDOW という名前のイベントが発生します。

通常はこのイベントが発生すると、destroy メソッドが実行されてアプリが終了しますが、protocol メソッドを利用すると、その処理を横取りして他の処理に置き換えることができます。

などと書かれており、イベントをハンドリングしているせいでウィンドウの破棄が行われず、 close メソッドの中でも destroy メソッドを呼ばす、結局の所ウィンドウが残って入力をハンドリングし続けているのでは?という感じもします。

まぁ先も言ったとおり自分はTkinterを知らないので正しいかどうかはわかりませんが、もしGitHubのissuesに書き込むのであれば、その辺りを突っつくか、なんでしたらこの質問のURLを貼り付けてもいいと思います。

投稿2024/09/13 12:34

katsuko

総合スコア3578

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.31%

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

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

質問する

関連した質問