前提・実現したいこと
wxpythonでgif動画を再生するデスクトップアプリを作っています。
10秒後にgif動画を切り替えたいだけなのですが、かなり苦戦しています。
Architectureと発生している問題・エラーメッセージ
wxのメイン画面を開き
↓
GIFクラスを呼び
↓
指定の動画(著作権フリーのgif)をwx.advで再生
↓
MyThreadEventとEVT_MY_THREADをバインド
↓
print("四.一")のwhileループ箇所(秒カウント箇所)でMyThreadEventを呼び
(ここで2重スレッド発生)
↓
EVT_MY_THREADに紐づくOnUpdateメソッドの実行
(この時、10秒経過しているか呼ばれたときに毎回チェック)
(if evt.msg>10 and self.status=='vacant' ここは常にvacantですので無視して下さい。)
(10秒経過したかどうかだけ検知しています。)
↓
10秒経過した時点でsomeiyoshino1.gifがDestroyもしくはSTOPされ、次のsomeiyoshino2.gifが再生されるはず…
チカチカとsomeiyoshino1.gifとsomeiyoshino2.gifが重なって表示されるだけでした。(Qモジュールの箇所をコメントアウトすればその現象を再現できます。)
python
1q = queue.Queue(1) # あってもなくても変わらない 2q.put('go') 3if(q.get() == 'stop')
上記の箇所をコメントアウトすれば、2つの動画が10秒後に重なってチカチカとなるところまではできました。
(4/26 21:15 一番下にそのソースコードを追記しました。)
あとは前動画を削除さえできればいいのではと思ってはいます。
queueモジュールを使ってしまうと、毎回('stop')であるか調べて、Destoroyをしようと思いましたが、なぜかコンソール上で停止してしまいました。
該当のソースコード
python
1import smtplib 2from email.mime.text import MIMEText 3import time 4import _thread 5import wx 6import wx.lib.newevent 7import queue 8import pdb 9import os 10import sys 11import cv2 12import numpy as np 13import wx.adv 14 15q = queue.Queue(1) # あってもなくても変わらない 16q.put('go') 17 18# 新しいイベントクラスとイベントを定義する 19(MyThreadEvent, EVT_MY_THREAD) = wx.lib.newevent.NewEvent() 20class MyThread: 21 def __init__(self, win): 22 self.win = win 23 self.i=0 24 print("一") 25 def Start(self): 26 self.keepGoing = True 27 self.running = True 28 print("MyThread.Start.running") 29 _thread.start_new_thread(self.Run, ()) 30 def Stop(self): 31 self.keepGoing = False 32 def IsRunning(self): 33 return self.running 34 def Run(self): 35 print("四.一") 36 while self.keepGoing: 37 38 # メッセージを格納したイベントを作る 39 #データ受信 40 41 self.i=self.i+1 42 print(self.i) 43 44 # (MyThreadEvent, EVT_MY_THREAD) = wx.lib.newevent.NewEvent() 45 # ↓ 46 # self.Bind(EVT_MY_THREAD, self.OnUpdate) 47 # この紐づきでMyThreadEventが呼ばれたときにEVT_MY_THREADイベントが実行されOnUpdateが呼ばれる 48 49 # つまりMyThreadEvent→EVT_MY_THREADイベント→OnUpdateという10秒経過したかチェックメソッドへ 50 evt = MyThreadEvent(msg=self.i) 51 52 # イベントを投げる 53 wx.PostEvent(self.win, evt) 54 time.sleep(1) 55 56 self.running = False 57 print("二") 58class dataserver: 59 def Start(self): 60 _thread.start_new_thread(self.Run, ()) 61 def Run(self): 62 print("八") 63 # self.lock=q.get() # あってもなくても変わらない 64 65class GIF(object): 66 def __init__(self,anime,id,gifname): 67 self.counter = 0 68 self.anime = anime 69 self.file = gifname 70 self.anime = anime 71 self.ani = wx.adv.Animation(self.file) 72 self.ctrl = wx.adv.AnimationCtrl(anime, -1, self.ani, pos=(10, 10)) 73 self.ctrl.Play() 74class GIF_Stop(object): 75 def __init__(self,anime,id,gifname): 76 self.counter = 0 77 self.anime = anime 78 self.file = gifname 79 self.anime = anime 80 self.ani = wx.adv.Animation(self.file) 81 self.ctrl = wx.adv.AnimationCtrl(anime, -1, self.ani, pos=(10, 10)) 82 self.ctrl.Stop() 83 time.sleep(5) 84class GIF_Destroy(object): 85 def __init__(self,anime,id,gifname): 86 self.counter = 0 87 self.anime = anime 88 self.file = gifname 89 self.anime = anime 90 self.ani = wx.adv.Animation(self.file) 91 self.ctrl = wx.adv.AnimationCtrl(anime, -1, self.ani, pos=(10, 10)) 92 self.ctrl.Stop() 93 self.ctrl.DestroyChildren() 94 95 96class MainWindow(wx.Frame): 97 def __init__(self, parent, id, title): 98 wx.Frame.__init__(self, parent, id, title, size=(300, 200)) 99 self.Center() 100 101 # パネル 102 self.display = wx.Panel(self, size=(300, 100), pos=(0, 0)) 103 self.display.SetBackgroundColour('#FFFAF0') 104 self.status = 'vacant' 105 106 # gif 107 self.MainPanel = wx.Panel(self, size=(1300, 900))#メイン画面の大きさ 108 self.anime = wx.Panel(self.MainPanel, pos=(0, 0),size=(1250, 850)) 109 self.anime.SetBackgroundColour("WHITE") 110 gifname = 'someiyoshino2.gif' 111 self.Motion = GIF(self.anime, id, gifname) 112 self.Fit() 113 114 print(q.get()) 115 if(q.get() == 'stop'): 116 gifname = 'someiyoshino2.gif' 117 self.Motion = GIF_Destroy(self.anime, id, gifname) 118 self.Fit() 119 gifname = 'someiyoshino1.gif' 120 self.Motion = GIF(self.anime, id, gifname) 121 self.Fit() 122 123 124 #テキスト 125 self.text1 = wx.StaticText(self.display,id, self.status) 126 font = wx.Font(20, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL) 127 self.text1.SetFont(font) 128 self.text1.Center() 129 130 self.reservation = wx.Panel(self,size=(300, 100), pos=(0, 100)) 131 self.button_1 = wx.Button(self.reservation,id, 'reserve', size=(100, 50)) 132 self.button_1.SetFont(font) 133 self.button_1.Bind(wx.EVT_BUTTON, self.click) 134 135 136 # 新しく定義したイベントに対応する処理関数をバインドする 137 print("三") 138 139 # つまりMyThreadEvent→EVT_MY_THREADイベント→OnUpdateという10秒経過したかチェックメソッドへ 140 self.Bind(EVT_MY_THREAD, self.OnUpdate) 141 print("四") 142 self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) 143 # スレッドのインスタンスを作り、起動する 144 # pdb.set_trace() 145 self.my_thread = MyThread(self) 146 self.my_thread.Start() 147 148 # ここから2重スレッド↓↓↓ 149 150 self.Centre() 151 self.Show(True) 152 print("五") 153 154 def click(self, event): 155 # mail1=mail() 156 if self.status == 'vacant': 157 print("六のあとにクリックしたらここにくる 七") 158 self.status='reserved' 159 self.text1.SetLabel(self.status) 160 self.data=dataserver() # あってもなくてもかわらない クラスの呼び方(インスタンス) 161 self.data.Start() 162 # q.put('locked') 163 self.button_1.Disable() 164 # mail1.message() 165 166 def OnCloseWindow(self, evt): 167 print("OnCloseWindow") 168 # スレッドが停止するまで待ってから、ウィンドウを閉じる 169 self.my_thread.Stop() 170 171 while self.my_thread.IsRunning(): 172 time.sleep(0.1) 173 self.Destroy() 174 175 # MyThreadEvent→EVT_MY_THREADイベント→OnUpdateという10秒経過したかチェックメソッドへ 176 def OnUpdate(self, evt): 177 print("六") 178 print("OnUpdate") 179 # スレッドからイベントを受信したときの処理 180 if evt.msg>10 and self.status=='vacant': 181 self.status='occupied' 182 self.text1.SetLabel(self.status) 183 # 10秒後にGIFをSTOP 184 q.put("stop") 185 186 187app = wx.App() 188MainWindow(None, wx.ID_ANY, 'TOTO') 189app.MainLoop()
試したこと
sqliteで変数をselectしてチェックする方法や、スレッド同時並行ではなく、プロセスを2つ作る方法なども試しましたが、いずれも次のgif再生はできませんでした。ただ動画の再生の切り替えだけなのですが、どなたかご存じの方教えて頂けないでしょうか。何か単純なミスをしているか、決定的な基礎知識が抜けている気がしてなりません。こんな需要はすぐに見つかるものだと思っていたのですが、調べてもわからなく困っています。どうかよろしくお願い致します。
補足情報(FW/ツールのバージョンなど)
win10
python3.7
wxpython
参考サイト
https://teratail.com/questions/158458
https://teratail.com/questions/233764
https://qiita.com/wikipediia/items/2919362de582a7d8de9e
https://www.python-beginners.com/entry/20191125/1574687207
https://qiita.com/asakbiz/items/5a34cae7b6c00c87a7e6
https://dev.classmethod.jp/articles/python-asyncio/
https://www.rhoboro.com/2019/02/09/coroutine-abstract.html
https://qiita.com/satsukiya/items/f7a3c7fdae566ed96306
https://www.yoheim.net/blog.php?q=20170601
2020/4/26 追記
Qモジュールを使わず、Onupdateメソッド内に動画切り替えメソッドを置いた場合のソースコードは以下になります。
python
1 2# q = queue.Queue(1) # あってもなくても変わらない 3# q.put('go') 4 5~ 6途中省略 7~ 8 9 # gif 10 self.MainPanel = wx.Panel(self, size=(1300, 900))#メイン画面の大きさ 11 self.anime = wx.Panel(self.MainPanel, pos=(0, 0),size=(1250, 850)) 12 self.anime.SetBackgroundColour("WHITE") 13 gifname = 'someiyoshino2.gif' 14 self.Motion = GIF(self.anime, id, gifname) 15 self.Fit() 16 17 18 #テキスト 19 self.text1 = wx.StaticText(self.display,id, self.status) 20 font = wx.Font(20, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL) 21 22~ 23途中省略 24~ 25 26 27 # MyThreadEvent→EVT_MY_THREADイベント→OnUpdateという10秒経過したかチェックメソッドへ 28 def OnUpdate(self, evt): 29 print("六") 30 print("OnUpdate") 31 # スレッドからイベントを受信したときの処理 32 if evt.msg>10 and self.status=='vacant': 33 self.status='occupied' 34 self.text1.SetLabel(self.status) 35 # 10秒後にGIFをSTOP 36 gifname = 'someiyoshino2.gif' 37 self.Motion = GIF_Destroy(self.anime, id, gifname) 38 self.Fit() 39 gifname = 'someiyoshino1.gif' 40 self.Motion = GIF(self.anime, id, gifname) 41 self.Fit() 42 43 44app = wx.App() 45MainWindow(None, wx.ID_ANY, 'TOTO') 46app.MainLoop()
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/04/26 23:19 編集
2020/04/26 23:28
2020/04/26 23:33 編集
2020/04/27 17:27
2020/04/27 22:15 編集