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

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

ただいまの
回答率

87.49%

[Python3] tkinter, 緊急停止ボタンの作成

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 1,282

score 23

■やりたいこと
1、 ラジオボタンにて帯域を選択したあと、チェックボックスを選択し、
【測定開始】ボタンを押した際に、常に前面に表示されるウィンドウを作りたい。

2、 サブウィンドウの中に「停止」ボタンを作りたい(ボタン作成のコードは作成したが反映しない)

■現状
【測定開始】ボタンを押した際に、一番最初に表示させたいサブウィンドウが、一番最後に表示されてしまう。
サブウィンドウの中に一つボタンを作りたいのだが、コードが反映していない。

from tkinter import *
from tkinter import ttk
from time import sleep

root = Tk()
root.title('測定CH設定')    
root.geometry("500x860+710+40")

Lframe1 = ttk.Labelframe(root, text='測定帯域選択', padding=5)
Lframe1.grid(row=0, column=0, columnspan=1, padx=15, pady=10, sticky='w')
Lframe2 = ttk.Labelframe(root, text='2.4GHz',padding=5)
Lframe2.grid(row=1,column=0, columnspan=1, padx=15, pady=10, sticky='nw')
Lframe3 = ttk.Labelframe(root, text='5GHz',padding=5)
Lframe3.grid(row=1,column=1, columnspan=1, padx=10, pady=10, sticky='w')

selected_frame = IntVar()

def change_selected_frame():
    if selected_frame.get() == 0:

        for child in Lframe2.winfo_children():
            child.configure(state='enable')
        for child in Lframe3.winfo_children():
            child.configure(state='disable')

    elif selected_frame.get() == 1:
        for child in Lframe2.winfo_children():
            child.configure(state='disable')
        for child in Lframe3.winfo_children():
            child.configure(state='enable')

    else:
        for child in Lframe2.winfo_children():
            child.configure(state='disable')
        for child in Lframe3.winfo_children():
            child.configure(state='disable')

Rbutton1 = ttk.Radiobutton(Lframe1, text='2.4GHz ', variable=selected_frame, value=0, command=change_selected_frame)
Rbutton1.grid(row=1,column=0,pady=5)
Rbutton2 = ttk.Radiobutton(Lframe1,text='5GHz', variable=selected_frame, value=1, command=change_selected_frame)
Rbutton2.grid(row=1,column=1,pady=5)

class val_2G:
    def __init__(self,name,set_frame,row_no):
        self.bool=BooleanVar()
        self.bool.set(False)
        self.name=name
        self.Cbtn=ttk.Checkbutton(set_frame, text=self.name, variable=self.bool)
        self.Cbtn.grid(row=row_no,column=0, columnspan=1, padx=15, pady=5, sticky='w')

class val_5G:
    def __init__(self,name,set_frame,row_no):
        self.bool=BooleanVar()
        self.bool.set(False)
        self.name=name
        self.Cbtn=ttk.Checkbutton(set_frame, text=self.name, variable=self.bool)
        self.Cbtn.grid(row=row_no,column=0, columnspan=1, padx=15, pady=5, sticky='w')

val_2G1=val_2G('CH1',Lframe2,6)
val_2G2=val_2G('CH2',Lframe2,7)
val_2G3=val_2G('CH3',Lframe2,8)
val_2G4=val_2G('CH4',Lframe2,9)
val_2G5=val_2G('CH5',Lframe2,10)
val_2G6=val_2G('CH6',Lframe2,11)
val_2G7=val_2G('CH7',Lframe2,12)
val_2G8=val_2G('CH8',Lframe2,13)
val_2G9=val_2G('CH9',Lframe2,14)
val_2G10=val_2G('CH10',Lframe2,15)
val_2G11=val_2G('CH11',Lframe2,16)
val_2G12=val_2G('CH12',Lframe2,17)
val_2G13=val_2G('CH13',Lframe2,18)
val_2G_list=[val_2G1, val_2G2, val_2G3, val_2G4, val_2G5, val_2G6, val_2G7, val_2G8, val_2G9, val_2G10, val_2G11, val_2G12, val_2G13]

val_5G36=val_5G('CH36',Lframe3,6)
val_5G40=val_5G('CH40',Lframe3,7)
val_5G44=val_5G('CH44',Lframe3,8)
val_5G48=val_5G('CH48',Lframe3,9)
val_5G52=val_5G('CH52',Lframe3,10)
val_5G56=val_5G('CH56',Lframe3,11)
val_5G60=val_5G('CH60',Lframe3,12)
val_5G64=val_5G('CH64',Lframe3,13)
val_5G100=val_5G('CH100',Lframe3,14)
val_5G104=val_5G('CH104',Lframe3,15)
val_5G108=val_5G('CH108',Lframe3,16)
val_5G112=val_5G('CH112',Lframe3,17)
val_5G116=val_5G('CH116',Lframe3,18)
val_5G120=val_5G('CH120',Lframe3,19)
val_5G124=val_5G('CH124',Lframe3,20)
val_5G128=val_5G('CH128',Lframe3,21)
val_5G132=val_5G('CH132',Lframe3,22)
val_5G136=val_5G('CH136',Lframe3,23)
val_5G140=val_5G('CH140',Lframe3,24)
val_5G_list=[val_5G36, val_5G40, val_5G44, val_5G48, val_5G52, val_5G56,val_5G60, val_5G64, val_5G100, val_5G104, val_5G108, val_5G112, val_5G116, val_5G120, val_5G124, val_5G128, val_5G132, val_5G136, val_5G140]


def check_all_2G_checkboxes():
    for val in val_2G_list:
        val.bool.set(True)

def clear_all_2G_checkboxes():
    for val in val_2G_list:
        val.bool.set(False)

def check_all_5G_checkboxes():
    for val in val_5G_list:
        val.bool.set(True)

def clear_all_5G_checkboxes():
    for val in val_5G_list:
        val.bool.set(False) 

def sub_window():
    sub_window = Toplevel()
    sub_window.title('緊急停止')
    sub_window.attributes("-topmost", True)
    sub_window.geometry("600x300+660+400")
    btn = ttk.Button(text='停止', padding=5)      ##ボタンが作成されない

def check_box():
    global checkbox

    sub_window()        ##一番最初に表示し緊急停止ボタンのように動かしたいのだが、一番最後に表示されてしまう

    selected_channels2 = []
    selected_channels5 = []

    if selected_frame.get() == 0:
        for val in val_2G_list:
            if val.bool.get():
                selected_channels2.append(val.name)

    elif selected_frame.get() == 1:
        for val in val_5G_list:
            if val.bool.get():
                selected_channels5.append(val.name)

    if len(selected_channels2) > 0:
        measure_channels2(selected_channels2)

    elif len(selected_channels5) > 0:
        measure_channels5(selected_channels5)

def measure_channels2(channels2):
    for channel2 in channels2:
        ch2 = channel2[2:]
        print(f'チャンネル {ch2} を測定中')
        sleep(5)
        print("測定終了")

def measure_channels5(channels5):
    for channel5 in channels5:
        ch5 = channel5[2:]
        print(f'チャンネル {ch5} を測定中')
        sleep(5)
        print("測定終了")

def quit():
    global checkbox
    checkbox.destroy()

btn1 = ttk.Button(Lframe2, text='全選択', padding=5, command=check_all_2G_checkboxes)
btn1.grid(row=5,column=0,pady=5)
btn2 = ttk.Button(Lframe2, text='全解除', padding=5, command=clear_all_2G_checkboxes)
btn2.grid(row=5,column=1,pady=5)
btn3 = ttk.Button(Lframe3, text='全選択', padding=5, command=check_all_5G_checkboxes)
btn3.grid(row=5,column=0,pady=5)
btn4 = ttk.Button(Lframe3, text='全解除', padding=5, command=clear_all_5G_checkboxes)
btn4.grid(row=5,column=1,pady=5)
btn5 = ttk.Button(text='測定開始', padding=5, command=check_box)
btn5.grid(row=5,column=0,pady=5)
btn6 = ttk.Button(text='キャンセル', padding=5, command=quit)
btn6.grid(row=5,column=1,pady=5)
selected_frame.set(-1) 
change_selected_frame() 

root.mainloop()

記述方法ご存知の方いらっしゃいましたら、ご教授頂けると幸いです。
よろしくお願いします。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

+1

サブウィンドウの中に一つボタンを作りたいのだが、コードが反映していない。

ボタンを作成しただけで、配置していないからです。適当なレイアウトマネージャ(pack()/grid()/place())を使って配置してください。

    # どのWindowに配置するのかを明記する
    btn = ttk.Button(sub_window, text='停止', padding=5)
    # 配置する
    btn.pack()

【測定開始】ボタンを押した際に、一番最初に表示させたいサブウィンドウが、一番最後に表示されてしまう。

今回のように時間がかかる処理を mainloopからのコールバック(check_box())内で実行してしまうと、処理が終了する(Returnが返る)までmainloop内の処理を行うことが出来なくなりますので、それまで新規のWindowは作成されません。またmainloopの処理が滞ることでWindowが固まるなどの不具合を引き起こしますので、コールバック関数内で時間のかかる処理を行うことはお勧めできません。

ですので、処理に時間がかかる処理(measure_channels2(),measure_channels5())を別スレッドにて実行するなどの対策を講じることで今回の不具合は解決するかと思います。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/11/06 12:53

    ご回答ありがとうございました。
    ボタンの配置に関しては、3つのレイアウトマネージャー全て試したのですが
    何も表示されなかったのでコードは記載しませんでした。
    解り辛くて申し訳ございません。
    エラーコードも出ないので、何が原因なのか解らず困っております。


    コールバック内での関数処理に関してありがとうございました。
    別スレッドにて動かせるように修正してみます。

    キャンセル

  • 2019/11/06 13:12

    Button() の第一引数に sub_window(buttonを配置する windowのインスタンス)を渡していないのではないでしょうか。
    回答にあるコードを参考にしてみてください

    キャンセル

  • 2019/11/07 14:27

    ありがとうございました!!
    やっと意味が理解できました。
    第一引数に、sub_window,を追記したところ
    サブウインドウの中にボタンが作成されました。
    ありがとうございました。

    キャンセル

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

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

関連した質問

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