92366


自己解決した内容ですが、共有のため投稿します。

# 動作概要

メインのGUIアプリケーションを起動する前に、設定ファイル等のチェックなど起動条件を確認し、最初にmessageboxによる注意喚起を行うことがあります。

その際、メインダイアログで正常に文字表示ができない、mainloopを抜けずに正常終了できない現象が発生しました。

# ソースコード

[code]

    import tkinter as tk
    from tkinter import messagebox
    
    
    def _message_box_(title: str, message: str) -> None:
        # messageboxの親となるroot
        root = tk.Tk()
        # 最前面へ移動
        root.attributes('-topmost', True)
        # ダイアログ非表示
        # ユーザーにはmessageboxだけ表示するため、ダイアログ非表示とする、
        root.withdraw()
        # 上位に移動
        root.lift()
        # フォーカスセット
        root.focus_force()
    
        messagebox.showinfo(title, message)
    
        return
    
    
    class act_dialog():
        def __init__(self):
            dialog = tk.Tk()
            dialog.title('main application')
            dialog.resizable(0, 0)
            dialog.lift()
            dialog.focus_force()
    
            message = tk.StringVar()
            message.set('Hello!!')
    
            label = tk.Label(dialog, textvariable=message)
            label.pack()
    
            dialog.mainloop()
    
            print('finish!!')
    
            return
    
    
    _message_box_('information', "Let's start!!")
    act_dialog()
    
[/code]


CC BY-SA 4.0
2022-11-22T00:30:21.393
92365
2022-11-22T00:30:21.393
32891
question
python tkinter
tkinter messageboxを最初に表示し、その後メインダイアログが正常に終了しない。


# 問題点

messageboxを単独表示させるためには、rootとなるダイアログが必要です。  
しかし、messagebox表示のたびにrootダイアログが表示されては見栄えも良くないので、withdraw()で非表示にします。  
rootの子にあたるmessageboxが閉じられても、rootが裏で生きています。  
非表示であるため、rootが生きていることが認識しづらい状態です。

メインダイアログ(act_dialog)で文字表示ができないのは、TKインスタンスの最初に生成されたものが優先されるというルールがあります。  
StringVar()での文字は、messageboxのために生成されたrootに割り当たってしまい、メインダイアログで文字表示できないという現象が出てきてしまいます。

逆に言うと、このような現象が発生した場合には、別のTKインスタンスがどこかでひっそりと生きていることになります。

二つ以上のダイアログを個別に生かす場合には、master引数があるメソッドにおいて、

[code]

    message = tk.StringVar(master=dialog)
    
[/code]

このようにmasterを指定する必要があります。

今回の問題点は、messageboxのためのrootを破棄していなかったため発生しました。  
きちんと理解して、destroy()しましょうという話です。

messageboxをだけ使用している場合には、スクリプト終了時に自動的にrootが破棄されるので、気づきにくいかと思います。

# 改善コード

[code]

    import tkinter as tk
    from tkinter import messagebox
    
    
    def _message_box_(title: str, message: str) -> None:
        # messageboxの親となるroot
        root = tk.Tk()
        # 最前面へ移動
        root.attributes('-topmost', True)
        # ダイアログ非表示
        # ユーザーにはmessageboxだけ表示するため、ダイアログ非表示とする、
        root.withdraw()
        # 上位に移動
        root.lift()
        # フォーカスセット
        root.focus_force()
    
        messagebox.showinfo(title, message)
    
        # 破棄
        root.destroy()
    
        return
    
    
    class act_dialog():
        def __init__(self):
            dialog = tk.Tk()
            dialog.title('main application')
            dialog.resizable(0, 0)
            dialog.lift()
            dialog.focus_force()
    
            message = tk.StringVar(master=dialog)
            message.set('Hello!!')
    
            label = tk.Label(dialog, textvariable=message)
            label.pack()
    
            dialog.mainloop()
    
            print('finish!!')
    
            return
    
    
    _message_box_('information', "Let's start!!")
    act_dialog()
    
    
[/code]


CC BY-SA 4.0
2022-11-22T00:30:21.393
92366
2022-11-22T00:30:21.393
32891
92365
answer