89071


題名の通り、tkinter,
threadingを使ってGUIのプログラミングを行なっています。そこで、「ある処理が終わると同時にtkinterの画面を非表示にする(削除する)」というものを考えているのですが、どうしてもうまくいきません。詳しい状況については、以下を見ていただきたいです。宿題などではないのですが、どうしても実装したいので、どうか、ご存知の方はご教授いただけますと大変幸いです。

ちなみに、自分の意図としては、1画面目でボタンが押されるとdestが実行され、root.destroy()が実行されるはずなので、この時点で想定する動作と異なっている理由がそもそもわかりません。また、2画面目が表示されない理由もわからないです。

### 想定する動作

  1. プログラムを実行すると、1画面目が表示される。
  2. OKボタンを押すと即時に1画面目が非表示となり、2画面目が表示される。
  3. 5秒後に2画面目も非表示となる。

### 実際の動作

  1. 想定通り
  2. OKボタンを押した5秒後に1画面目が非表示となり、2画面目はそもそも表示されない

**環境**

Python 3.7.1  
macOS

**コード**

[code]

    import tkinter
    import threading
    import time
    
    def dest(event):
        # ボタンが押されたら、画面を削除
        root1.destroy()
    
    # 第1画面の設定
    root1 = tkinter.Tk()
    root1.geometry(f"300x100")
    button_ok = tkinter.Button(root1, text="OK", width=5, height=2)
    button_ok.pack()
    button_ok.bind("<1>", dest)
    # 1画面目を表示する
    root1.mainloop()
    
    def threading_run(root):
        # ボタンが押された時、マルチスレッドで行う処理
        for i in range(4):
            time.sleep(1)
        print("finished")
    
        root.destroy()
    
    # 第2画面の設定
    root2 = tkinter.Tk()
    root2.geometry(f"300x300")
    label1 = tkinter.Label(text="5秒後に非表示")
    label1.pack()
    
    # スレッドスタート
    t = threading.Thread(target=threading_run(root2))
    t.start()
    
    root2.mainloop()
    
[/code]


CC BY-SA 4.0
2022-05-26T12:30:11.337
89069
2022-05-26T22:48:27.660
2022-05-26T16:17:56.670
3060
51915
question
python tkinter gui マルチスレッド
pythonにおいて、threading(マルチレッド)とtkinterで想定通りの動作をしない


おかしいのはスレッドを作成する指定ですね。

[code]

    t = threading.Thread(target=threading_run(root2))
    
[/code]

ここで`target=threading_run(root2)`と言う指定は、`threading_run()`という関数の呼び出し可能オブジェクトでは無く、`threading_run(root2)`を実行した結果(戻り値は無いので`None`)が`target`に設定されます。そして`None`が設定されるということは何も呼び出さないことになります。

[class threading.Thread(group=None, target=None, name=None, args=(),
kwargs={}, *,
daemon=None)](https://docs.python.org/ja/3/library/threading.html#threading.Thread)

> target は run()
> メソッドによって起動される呼び出し可能オブジェクトです。デフォルトでは何も呼び出さないことを示す`None`になっています。

呼び出しに必要なパラメータ`root2`は`args=()`というパラメータに指定しなければなりません。

> args は target を呼び出すときの引数タプルです。デフォルトは`()`です。

そしてタプルなので引数が１つだけの時は`args=(root2)`では駄目で`args=(root2,)`とする必要があります。  
[Pythonのスレッドで引数を渡せなくて躓いた話。](https://meiei.hatenablog.com/entry/2019/12/17/213639)

なお、上記を行っても2つ目の画面は表示されて5秒後に消えますが、スクリプトは終了しません。  
それは作成したスレッドが終了していないからです。

簡単な対処法としては、スレッド作成時に`daemon=`パラメータを使ってデーモンスレッドに指定することです。

> daemon  
>  このスレッドがデーモンスレッドか (True) か否か (False) を示すブール値。この値は start()
> の呼び出し前に設定されなければなりません。さもなければ RuntimeError が送出されます。

画面が消えてmainloopが終了し、スクリプトの終端まで行った時に自動的にデーモンスレッドも終了することになります。

なので問題の行は2つを併せて以下のようにする必要があります。

[code]

    t = threading.Thread(target=threading_run, args=(root2,), daemon=True)
    
[/code]


CC BY-SA 4.0
2022-05-26T15:47:09.840
89071
2022-05-26T22:48:27.660
2022-05-26T22:48:27.660
26370
26370
89069
answer