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

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

ただいまの
回答率

87.61%

tkinterの違いボダン関数からプッシュアウトグラフを一斉消したい

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 95

score 12

rootに2Dボタン、3DボタンとENDブタンがあります。2Dと3Dをクリックすると、それぞれ対応したデータを処理して、plt.plotの2D、3Dグラフが表示させます。そして、ENDボタンで、終了したいですが、rootを終了できましたが、プッシュアウトした(plt.show())グラムが残りました。

どうすれば、ENDボタンで、グラムを含めて、一斉に終了できますか?教えてください。よろしくお願いします。

import tkinter,os
import matplotlib.pyplot as plt
from tkinter import *
from tkinter import ttk

#終了ブタン
def button_end():
    root.quit()
    root.destroy()

#2Dグラフ
def button_2d():
    global raw_data,second,data_name
    if second ==None or not second.winfo_exists():
        second = tkinter.Toplevel()
        second.title("2d")
        second.geometry()
    x=[1,2,3,4,5]
    y=[2,3,1,4,8]
    plt.plot(x,y)
    second.destroy()
    plt.show()

#3Dグラフ
def button_3d():
    global raw_data,third,data_name
    if third ==None or not third.winfo_exists():
        third = tkinter.Toplevel()
        third.title("3d")
        third.geometry()

    fig = plt.figure(figsize=(6,6))
    ax = fig.add_subplot(111, projection='3d')

    x=[1,2,3,4,5]
    y=[8,4,1,2,1]
    z=[2,4,6,8,10]

    ax.plot(x, y, z)
    third.destroy()
    plt.show()

if __name__ == " __main__":
    def main():
        pass
root = tkinter.Tk()
root.title("test")
root.geometry("+0+0")
second = None
third = None
frame_top     = Frame(root, bd=4, relief=GROOVE)

# widgetの設定
btn_end       = ttk.Button(frame_top,text='END',command = button_end)
btn_2d       = ttk.Button(frame_top,text='2D', command = button_2d)
btn_3d       = ttk.Button(frame_top,text='3D', command = button_3d)
# widgetの配置
frame_top.grid (row = 0, column = 0, sticky = W) #in root
btn_2d.grid(row=0,column=1,sticky = W)    #in frame_top
btn_3d.grid(row=0,column=2,sticky = N)    #in frame_top
btn_end.grid(row=0,column=3,sticky = N)      #in frame_top
root.mainloop()


環境:Win10、Python3.8

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

check解決した方法

0

subwindowをやめました。Figも一つにまとめました。

何かございましたら、ご指摘をいただくようにお願いします。

import tkinter,os
import matplotlib.pyplot as plt
from tkinter import *
from tkinter import ttk

def button_end():
    root.quit()
    root.destroy()
    plt.close()

def button_2d():
    plt.clf()
    x=[1,2,3,4,5]
    y=[2,3,1,4,8]
    a = plt.plot(x,y)

    #plt.show(block=False) (しなくでも、いいです。)
  plt.show()

def button_3d():

    plt.clf()

    ax = fig.add_subplot(111, projection='3d')

    x=[1,2,3,4,5]
    y=[8,4,1,2,1]
    z=[2,4,6,8,10]

    ax.plot(x,y, z)
    #plt.show(block=False) (しなくでも、いいです。)
    plt.show()

if __name__ == " __main__":

    def main():
        pass

root = tkinter.Tk()
root.title("test")
root.geometry("+0+0")

frame_top     = Frame(root, bd=4, relief=GROOVE)

# widgetの設定
btn_end       = ttk.Button(frame_top,text='END',command = button_end)
btn_2d       = ttk.Button(frame_top,text='2D', command = button_2d)
btn_3d       = ttk.Button(frame_top,text='3D', command = button_3d)

# widgetの配置
frame_top.grid (row = 0, column = 0, sticky = W) #in root

btn_2d.grid(row=0,column=1,sticky = W)    #in frame_top
btn_3d.grid(row=0,column=2,sticky = N)    #in frame_top
btn_end.grid(row=0,column=3,sticky = N)      #in frame_top


fig = plt.figure(figsize=(6,6))

root.mainloop()

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2021/09/16 18:35

    以下のサイトを参考しました。
    https://qiita.com/Gyutan/items/e753700011439057156f

    キャンセル

  • 2021/09/17 08:58

    > plt.show(block=False) (しなくでも、いいです。)

    見た目の挙動的には問題ないかもしれませんが、
    内部の動作的には2点程問題があります。

    [1] mainloop と plt.show の併用は、イベントループの競合
    [2] バックエンドが異なる場合、tkinter はフリーズする

    例えば、button_2d を呼び出した後に、button_3d を呼び出した場合の関数の呼び出しが

    mainloop
     button_2d
      plt.show
       button_3d # 問題点: 関数 button_2d 内の plt.show 内で呼び出される
        plt.show

    plt.show() 呼び出しはブロッキング処理になり、
    その後のコードは内部のループを抜けるまで実行されません。

    tkinter の GUI のイベントは mainloop で処理されてるのですが、
    button_2d を呼び出した後に mainloop に戻らないと tkinter がフリーズする可能性があります。
    問題ない場合は、plt.show のバックエンドが tkinter で、
    plt.show 内部で tkinter のイベントが処理されている場合に限ります。


    # block=False にすることで mainloop に処理が戻り、
    # button_3d は mainloop から呼び出される

    mainloop
     button_2d
      plt.show(block=False)
     button_3d
      plt.show(block=False)

    バックエンド次第では plt.show(block=False) を定期的に呼び出す必要があったり
    plt.show 呼び出し自体不要な場合もあります。もし、他の環境で動かす予定がある場合は、
    環境の違いにより挙動が異なる可能性がある点に注意してください。

    キャンセル

  • 2021/09/17 11:16

    ご教授ありがとうございました。よく勉強になりました。

    キャンセル

0

plot.showにオプション引数block=Falseを指定しておけば、plt.showのウィンドウが表示されている間もrootウィンドウを操作でき、ENDボタンを押すとrootウィンドウとplt.showのウィンドウが共に閉じるはずです。

block=Falseを指定しない、あるいはblock=Trueを指定すると、plt.showのウィンドウを閉じるまでrootウィンドウは操作に反応しなくなります。

もっとも、その間もイベントは貯えられているので、ENDボタンを押し(この時点では何も起きない)→plt.showのウィンドウを閉じる→(このタイミングでENDボタンが押されて)rootウィンドウが閉じる、という動作になります。


IDLEから実行した場合は、rootウィンドウを閉じても、それまでに開いたplt.showのウィンドウは閉じません。これは、IDLEのウィンドウ("IDLE Shell X.X.X"と書いてあるほう)でPythonのプロセスが実行中のままになっていて、その子プロセスであるplt.showのウィンドウも閉じないのだと思われます。

実際に、IDLEのウィンドウ("IDLE Shell X.X.X"と書いてあるほう)を閉じると、plt.showのウィンドウも一緒に閉じますし、「Run」→「Run... Customized」(Shift-F5キー)でコードを実行する際に「Restart Shell」にチェックを付けても、古いplt.showのウィンドウは閉じます。

ということで、IDLEでは「ENDボタンを押すとplt.showのウィンドウも閉じる」という動作を実現するのは無理ですね。Visual Studio Codeへの移行を考えられてはどうでしょうか。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2021/09/16 15:26

    何か根本的な課題があると思います。しっかり勉強させていただきます。

    キャンセル

  • 2021/09/16 17:49

    横からコメント失礼します。
    matplot.pyplot のバックエンドについて調べて見て下さい。

    tkinter 以外のバックエンドが選ばれている場合、
    別のGUIライブラリでグラフが表示されてるので、
    tkinter のウィンドウを閉じても、想定されてるような挙動にならない可能性があります。

    解消方法としては2通り
    - バックエンドに tkinter が使われるものを選ぶ。→ 回答で想定されてるような挙動になるはずです。
    - plt.show を使わずに、tkinter に埋め込む方法で実装する。
    (検索用ヒント: FigureCanvasTkAgg)

    キャンセル

  • 2021/09/16 17:56

    teamikl様

    ありがとうございました。後ほど、やってみます。ちなみに、私が解決方法を見つけました。Daregada様のヒントを参考しました。ありがとうございました。

    キャンセル

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

  • ただいまの回答率 87.61%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る