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

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

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

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

Tkinter

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

Q&A

解決済

1回答

2502閲覧

Python3 Tkinter Toplevelの挙動が意図したものと異なる

person

総合スコア223

Python 3.x

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

Tkinter

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

0グッド

0クリップ

投稿2020/11/20 01:15

編集2020/11/24 00:13

実現したいこと

Python実行時にウィンドウにあるボタンを押すと、ポップアップウィンドウが最前面に1つ表示される。
ポップアップが開いている間は、後ろのウィンドウを操作できなくする

ポップアップウィンドウにあるボタンを押すと、さらにポップアップウィンドウが最前面に1つ表示される。
2つめのポップアップが開いている間は、後ろの2つのウィンドウを操作できなくする。

問題点

Windowsでは実現できているが、Raspberry Piだと実現できていない。

Raspberry Piの挙動(Windowsとの相違点)

  • 後ろのウィンドウをクリックしたときに、Windowsだとクリック中のみ後ろのウィンドウがアクティブになり、Raspberry Piだとクリックしたウィンドウがアクティブになる(アクティブになった後はそのまま)
  • Raspberry Piだと後ろのウィンドウの閉じる・最小化・最大化が操作でき、Windowsだとできない
  • Raspberry Piだと win の閉じるボタンを押すと前面のウィンドウが全て閉じるが、Windowsだと閉じない
  • Raspberry Piだと sub2_win が開いている状態で sub1_win の閉じるボタンを押すと、sub1_win は閉じるが sub2_win は閉じない。Windowsだと最前面以外のウィンドウを閉じることはできない
  • 背景をクリックした後ウィンドウをクリックすると、Raspberry Piだとクリックしたウィンドウがアクティブになり、Windowsだと最前面のウィンドウがアクティブになる

Raspberry Piの挙動(Windowsと同じ)

  • 背景をクリックすると、Tk()、Toplevel()は非アクティブになる

(ここでいうアクティブとは、添付画像のようにウィンドウが選択状態であることです。タイトルバーが青くなっている部分です。)

イメージ説明

質問

Windowsのような挙動が理想ですが、Raspberry Piで同じ挙動を実現させるための対処方法はありますか。

ソースコード

Python

1import tkinter as tk 2 3def open_sub2_win(win, sub1_win): 4 sub2_win = tk.Toplevel() 5 sub2_win.title("sub2_win") 6 sub2_win.geometry("300x300+200+200") 7 sub2_win.transient(sub1_win) 8 sub2_win.grab_set() 9 sub2_win.focus_set() 10 sub2_win.protocol("WM_DELETE_WINDOW", lambda:close_sub1_win(sub2_win)) 11 12def close_sub2_win(sub2_win): 13 sub2_win.grab_release() 14 sub2_win.destroy() 15 16def open_sub1_win(win): 17 sub1_win = tk.Toplevel() 18 sub1_win.title("sub1_win") 19 sub1_win.geometry("300x300+100+100") 20 sub1_win.transient(win) 21 sub1_win.grab_set() 22 sub1_win.focus_set() 23 sub1_win.protocol("WM_DELETE_WINDOW", lambda:close_sub1_win(sub1_win)) 24 btn = tk.Button(sub1_win, text="open_sub2_win", command=lambda:open_sub2_win(win, sub1_win)) 25 btn.grid() 26 27def close_sub1_win(sub1_win): 28 sub1_win.grab_release() 29 sub1_win.destroy() 30 31win = tk.Tk() 32win.title("win") 33win.geometry("300x300+0+0") 34 35btn = tk.Button(win, text="open_sub1_win", command=lambda:open_sub1_win(win)) 36btn.grid() 37 38win.mainloop()

追記

ラズパイで、最前面ウィンドウのみ閉じる・最大化ボタンのみ効くように変更。

Python

1import tkinter as tk 2 3def open_sub2_win(win, sub1_win): 4 global win_flag, sub1_flag, sub2_flag 5 sub1_win.resizable(0, 0) 6 win_flag = False 7 sub1_flag = False 8 sub2_flag = True 9 10 sub2_win = tk.Toplevel() 11 sub2_win.title("sub2_win") 12 sub2_win.geometry("300x300+200+200") 13 sub2_win.transient(sub1_win) 14 sub2_win.grab_set() 15 sub2_win.focus_set() 16 sub2_win.protocol("WM_DELETE_WINDOW", lambda:close_sub2_win(sub1_win, sub2_win)) 17 18 19 20def close_sub2_win(sub1_win, sub2_win): 21 global win_flag, sub1_flag, sub2_flag 22 if sub2_flag == True: 23 sub2_win.grab_release() 24 sub2_win.destroy() 25 win_flag = False 26 sub1_flag = True 27 sub2_flag = False 28 sub1_win.resizable(1, 1) 29 30 31def open_sub1_win(win): 32 global win_flag, sub1_flag, sub2_flag 33 win.resizable(0, 0) 34 win_flag = False 35 sub1_flag = True 36 sub2_flag = False 37 38 sub1_win = tk.Toplevel() 39 sub1_win.title("sub1_win") 40 sub1_win.geometry("300x300+100+100") 41 sub1_win.transient(win) 42 sub1_win.grab_set() 43 sub1_win.focus_set() 44 sub1_win.protocol("WM_DELETE_WINDOW", lambda:close_sub1_win(win, sub1_win)) 45 btn = tk.Button(sub1_win, text="open_sub2_win", command=lambda:open_sub2_win(win, sub1_win)) 46 btn.grid() 47 48 49 50def close_sub1_win(win, sub1_win): 51 global win_flag, sub1_flag, sub2_flag 52 if sub1_flag == True: 53 sub1_win.grab_release() 54 sub1_win.destroy() 55 win_flag = True 56 sub1_flag = False 57 sub2_flag = False 58 win.resizable(1, 1) 59 60def close_win(win): 61 global win_flag, sub1_flag, sub2_flag 62 if win_flag == True: 63 win.destroy() 64 65win_flag = True 66sub1_flag = False 67sub2_flag = False 68 69win = tk.Tk() 70win.title("win") 71win.geometry("300x300+0+0") 72 73btn = tk.Button(win, text="open_sub1_win", command=lambda:open_sub1_win(win)) 74btn.grid() 75 76win.protocol("WM_DELETE_WINDOW", lambda:close_win(win)) 77win.mainloop() 78

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

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

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

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

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

guest

回答1

0

ベストアンサー

Raspberry Piはハードウェアなので、OSを書かないと環境がわからないですよ。
ただWindowsで想定通りの動作している以上ソースコード的には間違ってないと思います。
Raspberry Piのほうも最前ウィンドウは変わらないようなので、grab_setの仕様の問題なのかなと。

さしあたり「後ろのウィンドウの閉じる・最小化・最大化が操作できる」が問題だと思うので、open_sub1_winやopen_sub2_winの中で隠れる側の操作を無効化することを考えてはどうでしょうか。
close_..の際にどうにか戻さないといけないですが。

投稿2020/11/20 16:53

gasbombe

総合スコア204

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

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

person

2020/11/24 02:07 編集

回答ありがとうございます。 > 隠れる側の操作を無効化することを考えてはどうでしょうか。 grab_set()でウィジェットの無効化はできていると思うのですが、 タイトルバーの操作はラズパイではできてしまいます。 (そもそもタイトルバーの操作を勝手に制限してくれるのはWindowsだけなのかもしれませんが。) 閉じるボタンは、WM_DELETE_WINDOWで検出できるので、フラグで処理を限定してみました。最大化は、ウィンドウオープン・クローズ時にresizable()で設定するようにしました。最小化の検出・設定は自分で調べた限り出てきませんでした。 (最小化の検出はbindで<Unmap>で可能。制限は無理か?) (質問文の方に、閉じる・最大化ボタン制限のソースコード記載) ラズパイのバージョン $ lsb_release -a No LSB modules are available. Distributor ID: Raspbian Description: Raspbian GNU/Linux 9.13 (stretch) Release: 9.13 Codename: stretch
person

2020/11/25 04:11

overrideredirect()やattributes("-fullscreen", 1)など、最小化を表示しない方法もありましたが、無効にするのは見つかりませんでした。 とりあえずは追記した方法でプログラムを組むことにします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問