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

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

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

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

Tkinter

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

Q&A

解決済

1回答

770閲覧

Pythonのtkinterを用いたGUIアプリケーションでボタンを押した際の動作が実行できない

hokahomu

総合スコア38

Python 3.x

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

Tkinter

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

0グッド

0クリップ

投稿2018/12/04 08:48

編集2018/12/05 08:13

前提・実現したいこと

tkinterを用いたGUIのアプリケーションを作っているのですが、実行ボタンが押された際に関数を実行して目的の動作を行わせ、停止ボタンが押された際に停止させようと思っています。ボタンを押した際の動作はうまくいったのですが、停止ボタンを押そうとしてもstartの関数内でループしてしまい停止ボタンを押すことができません、どうすればよいでしょうか

該当のソースコード

Python

1from mutagen.mp3 import MP3 as mp3 2import numpy as np 3import cv2 4import pygame 5import time 6import threading 7import sys 8import tkinter 9 10root =tkinter.Tk() 11root.title(u"app") 12root.geometry("600x700") 13 14def end1(): 15 t=1 16 17def getCircle1(frame, lower_color, upper_color): 18 MIN_RADIUS = 25 19 20 # HSVによる画像情報に変換 21 hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) 22 23 # ガウシアンぼかしを適用して、認識精度を上げる 24 blur = cv2.GaussianBlur(hsv, (9, 9), 0) 25 26 # 指定した色範囲のみを抽出する 27 color = cv2.inRange(blur, lower_color, upper_color) 28 29 # オープニング・クロージングによるノイズ除去 30 element8 = np.array([[1, 1, 1], [1, 1, 1], [1, 1, 1]], np.uint8) 31 oc = cv2.morphologyEx(color, cv2.MORPH_OPEN, element8) 32 oc = cv2.morphologyEx(oc, cv2.MORPH_CLOSE, element8) 33 34 # 輪郭抽出 35 img, contours, hierarchy = cv2.findContours(oc, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) 36 print("{} contours.".format(len(contours))) 37 38 if len(contours) > 0: 39 # 一番大きい赤色領域を指定する 40 contours.sort(key=cv2.contourArea, reverse=True) 41 cnt = contours[0] 42 43 # 最小外接円を用いて円を検出する 44 (x, y), radius = cv2.minEnclosingCircle(cnt) 45 center = (int(x), int(y)) 46 radius = int(radius) 47 48 49 # 円が小さすぎたら円を検出していないとみなす 50 if radius < MIN_RADIUS: 51 return None 52 else: 53 return center, radius 54 else: 55 return None 56 57def getCircle2(frame, lower_color, upper_color): 58 MIN_RADIUS = 25 59 60 # HSVによる画像情報に変換 61 hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) 62 63 # ガウシアンぼかしを適用して、認識精度を上げる 64 blur = cv2.GaussianBlur(hsv, (9, 9), 0) 65 66 # 指定した色範囲のみを抽出する 67 color = cv2.inRange(blur, lower_color, upper_color) 68 69 # オープニング・クロージングによるノイズ除去 70 element8 = np.array([[1, 1, 1], [1, 1, 1], [1, 1, 1]], np.uint8) 71 oc = cv2.morphologyEx(color, cv2.MORPH_OPEN, element8) 72 oc = cv2.morphologyEx(oc, cv2.MORPH_CLOSE, element8) 73 74 # 輪郭抽出 75 img, contours, hierarchy = cv2.findContours(oc, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) 76 print("{} contours.".format(len(contours))) 77 78 if len(contours) > 0: 79 # 一番大きい赤色領域を指定する 80 contours.sort(key=cv2.contourArea, reverse=True) 81 cnt = contours[0] 82 83 # 最小外接円を用いて円を検出する 84 (x, y), radius = cv2.minEnclosingCircle(cnt) 85 center = (int(x), int(y)) 86 radius = int(radius) 87 88 89 # 円が小さすぎたら円を検出していないとみなす 90 if radius < MIN_RADIUS: 91 return None 92 else: 93 return center, radius 94 else: 95 return None 96 97def start(): 98 99 # 内蔵カメラを起動(カメラが一つしか繋がっていない場合は、引数に0を渡せば良い) 100 cap = cv2.VideoCapture(1) 101 102 flgb1=0 103 flgt1=0 104 flgb2=0 105 flgt2=0 106 107 while True: 108 109 # 赤色の円を抽出する 110 frame = cap.read()[1] 111 getframe1 = getCircle1(frame, np.array([130,80,80]), np.array([200,255,255])) 112 #黄色の円を検出 113 getframe2 = getCircle2(frame, np.array([30,50,50]), np.array([80,255,255])) 114 115 #赤が見つかったら 116 if getframe1 is not None: 117 # 見つかった円の上に青い円を描画 118 # getframe[0]:中心座標、getframe[1]:半径 119 cv2.circle(frame, getframe1[0], getframe1[1], (255, 0, 0), 2) 120 if flgb1==0:#flgb1が0の時 121 filename = 'ファイルパス' #再生したいmp3ファイル 122 pygame.mixer.init() 123 pygame.mixer.music.load(filename) #音源を読み込み 124 mp3_length = mp3(filename).info.length #音源の長さ取得 125 pygame.mixer.music.play(1) #再生開始。1の部分を変えるとn回再生(その場合は次の行の秒数も×nすること) 126 time.sleep(mp3_length + 0.25) #再生開始後、音源の長さだけ待つ(0.25待つのは誤差解消) 127 pygame.mixer.music.stop() #音源の長さ待ったら再生停止 128 flgb1=1#flgb1に1を代入し一回だけの処理 129 flgt1=0#flgt1に0を代入し時間処理を可能にする 130 at1=time.time()+5#今の時間+5秒 131 132 #黄色が見つかったら 133 if getframe2 is not None: 134 # 見つかった円の上に青い円を描画 135 # getframe[0]:中心座標、getframe[1]:半径 136 cv2.circle(frame, getframe2[0], getframe2[1], (255, 0, 0), 2) 137 if flgb2==0:#flgb2が0の時 138 filename = 'ファイルパス' #再生したいmp3ファイル 139 pygame.mixer.init() 140 pygame.mixer.music.load(filename) #音源を読み込み 141 mp3_length = mp3(filename).info.length #音源の長さ取得 142 pygame.mixer.music.play(1) #再生開始。1の部分を変えるとn回再生(その場合は次の行の秒数も×nすること) 143 time.sleep(mp3_length + 0.25) #再生開始後、音源の長さだけ待つ(0.25待つのは誤差解消) 144 pygame.mixer.music.stop() #音源の長さ待ったら再生停止 145 flgb2=1#flgb2に1を代入し一回だけの処理 146 flgt2=0#flgt2に0を代入し時間処理を可能にする 147 at2=time.time()+5#今の時間+5秒 148 149 nt1=time.time() 150 nt2=time.time() 151 152 if flgb1==1 and flgt1==0 and at1<=nt1: 153 flgb1=0 154 flgt1=1 155 156 if flgb2==1 and flgt2==0 and at2<=nt2: 157 flgb2=0 158 flgg2=1 159 160 # 検出結果とともに映像を表示 161 cv2.imshow('Circle Detect', frame) 162 163 164 if cv2.waitKey(1) & 0xFF == ord('q'): 165 break 166 167 # 終了時にカメラを解放 168 cap.release() 169 cv2.destroyAllWindows() 170 171btn1=tkinter.Button(root, text='aモード 開始',font=(" ",20),bg='#f0e68c',fg='#ff0000',height=5,width=14,command=start) 172btn1.place(x=50,y=170) 173 174btn2=tkinter.Button(root, text='aモード 停止',font=(" ",20),bg='#f0e68c',fg='#ff0000',height=5,width=14,command=end1) 175btn2.place(x=340,y=170) 176 177root.mainloop() 178 179

試したこと

ボタンが押された際にstartの関数を呼び出し、動作させることに成功した。
停止ボタンが押された際にstart内の動作を停止させたい。

補足情報(FW/ツールのバージョンなど)

python3.7
opencv-python(3.4.3.18)
numpy(1.15.1)
pygame(1.9.4)
muatagen(1.41.1)

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

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

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

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

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

guest

回答1

0

ベストアンサー

今回のように連続的な処理を行う場合は、その処理を Buttonからのイベント関数内で行うのではなく別スレッドにて行うようにし、Buttonからのイベント関数では単にスレッドの開始処理、停止処理のみを行うようにします。

質問に挙げていただいたアプリを動作させる環境が整わなかったので、とりあえず雛形となるスレッドを動作させる部分のみのサンプルを提示しておきますので参考にしてください

Python

1import numpy as np 2import time 3import threading 4import tkinter 5 6root =tkinter.Tk() 7root.title(u"app") 8root.geometry("600x700") 9 10thread = None 11running = False 12 13def DoSomething(): 14 global running 15 16 # ここ以下メインとなる処理を書く 17 # Stopボタンが押された場合, end関数内で running を Falseにするので 18 # 速やかにこの関数内の処理を終了するようにしてください 19 20 running = True 21 print("Thread Start") 22 while running: 23 print("MainLoop") 24 time.sleep(1) 25 26 print("Thread Stop") 27 28 29def start(): 30 global thread 31 32 # スレッドが既に停止している場合は無視 33 if thread is not None: 34 return 35 # DoSomething関数を別スレッドで実行する 36 thread = threading.Thread(target=DoSomething) 37 thread.start() 38 39 40def end(): 41 global running,thread 42 43 # スレッドが既に停止している場合は無視 44 if thread is None: 45 return 46 47 # runningフラグを落とす。DoSomething関数が終了するハズ 48 running = False 49 # スレッドが停止するまで待つ 50 thread.join() 51 thread = None 52 53 54btn1=tkinter.Button(root, text='aモード 開始',font=(" ",20),bg='#f0e68c',fg='#ff0000',height=5,width=14,command=start) 55btn1.place(x=50,y=170) 56 57btn2=tkinter.Button(root, text='aモード 停止',font=(" ",20),bg='#f0e68c',fg='#ff0000',height=5,width=14,command=end) 58btn2.place(x=340,y=170) 59 60root.mainloop()

投稿2018/12/06 05:06

magichan

総合スコア15898

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

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

hokahomu

2018/12/06 08:13

ありがとうございます! 何とか無事に完成させることができました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問