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

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

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

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

Tkinter

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

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

1804閲覧

tkinterでmp3を数回鳴らすと、エラーメッセージが出る。

Le8

総合スコア1

Python 3.x

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

Tkinter

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

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2021/09/19 06:50

前提・実現したいこと

プログラミング初心者です。
PythonのTkinterでクイズのアプリを作っています。
正解、不正解のBGMを鳴らすときに、
音は出るのですが、2問目以降に以下のエラーメッセージが表示されてしまいます。

発生している問題・エラーメッセージ

raise RuntimeError('EventLoop.run() must be called from the same ' + RuntimeError: EventLoop.run() must be called from the same thread that imports pyglet.app

該当のソースコード

python,tkinter

1 2# 選択肢の正誤判定 3# aは自分の解答番号、nqは問題番号、dataは問題の入ったリスト 4# data[nq][5]は問題の答えの番号です。 5# judge()は他の場所で使っています。 6 7def judge(a): 8 global nq 9 if data[nq][5] == a: 10 StatusLabel.configure(text='正解') 11 playSound_t() 12 elif data[nq][5] != a: 13 StatusLabel.configure(text='不正解') 14 playSound_f() 15 16 17# サウンドのスタート 18def startPlaying_f(): 19 player.queue(music_file_f) 20 player.play() 21 pyglet.app.run() 22 23 24def startPlaying_t(): 25 player.queue(music_file_t) 26 player.play() 27 pyglet.app.run() 28 29 30# サウンドの再生 31def playSound_f(): 32 global sound_thread 33 sound_thread = Thread(target=startPlaying_f) 34 sound_thread.start() 35 36 37def playSound_t(): 38 global sound_thread 39 sound_thread = Thread(target=startPlaying_t) 40 sound_thread.start() 41 42 43# 閉じるボタンの動作 44def quit(event=None): 45 root.destroy() 46 47 48root = tk.Tk() 49player = pyglet.media.Player() 50path_sound_f = 'false.mp3' 51path_sound_t = 'true.mp3' 52music_file_f = pyglet.media.load(path_sound_f) 53music_file_t = pyglet.media.load(path_sound_t) 54 55root.mainloop() 56pyglet.app.exit()

試したこと

pyglet.app.runとpyglet.exitの場所の変更は、少し試しましたが、エラーメッセージが消えません。

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

ここにより詳細な情報を記載してください。

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

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

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

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

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

guest

回答1

0

ベストアンサー

python

1RuntimeError: EventLoop.run() must be called from the same thread that imports pyglet.app

問題点1: 複数のスレッドからスレッドを跨いで player を操作してます。

質問に掲載されてるコードだけでは問題を再現できませんが、
スレッドで呼ばれる関数内に player が無い事から推測して
変数 player は、外側(メインスレッド)で初期化されているようなので、
pyglet の初期化と実行が別スレッドで行われている、
スレッドセーフな利用ではない為エラーが報告されてます。

解決策A: スレッドを用いる場合は、スレッドで呼ばれる関数内で完結する。
tkinter とは queue 等を用いてメッセージをやり取りする。
解決案B: スレッドは使わず、tkinter のタイマー内で pyglet のイベント処理を呼び出す。
解決案C: メインスレッドで pyglet.media を非同期で使う。
(pyglet の利用がオーディオ再生用のみの場合に限る)


問題点2:
エラー自体の解消は、同じスレッドで行うようにすればよいのですが、
2回目の呼び出しとなった時は pyglet のイベントループである
`app.run()' が複数回呼ばれないようにする工夫も必要になってきます。

  • A: 毎回 app.run/app.exit する

 exit は 2回目の run の前に呼び出されるようにします。

  • B: 初回のみ app.run を呼び出し、 queue でメッセージを送る。
  • C: pyglet のイベントループを独自に作る

※ライブラリ側ではサポートされてない為、こういった動作をする枠組みを自分で実装する必要があります。
Queue を用いてスレッド間でメッセージをやり取りする方法が一般的です。
(追記: プログラミング初心者との事なので、難しいかもしれません。
tkinter/pyglet の用例は少ないので、応用が必要になってきます)

クリックの度に新しくスレッドを作成しているのも問題の為、

  • メインスレッド: tkinter (pyglet は直接扱わない)
  • サブスレッド(1つのみ): pyglet (tkinter は直接扱わない)

というような構成にすると、自然にスレッドを跨ぐリソースの操作
スレッドセーフではない操作を抑制できます。


暫定的な問題の回避策

python

1 # run 呼び出し後、3秒後に exit を呼び出し 2 pyglet.clock.schedule_once( 3 lambda _: pyglet.app.exit(), 3) 4 pyglet.app.run() 5 # 3秒後に run() を抜けるので、 6 # ** run() を抜けた後ならば ** 7 # 2回目のrun()が多重に呼ばれるのを回避できます。 8

毎回、開始・終了するので、実行効率的には良い方法ではありません。
他の方法と比べて、コードの変更量が少なく済むので提示しましたが、
音声再生中に重ねてボタンが押された場合等も、考慮してません。
問題点の確認・動作の把握の為の参考程度にして下さい。

投稿2021/09/20 07:07

編集2021/09/20 07:15
teamikl

総合スコア8664

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

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

Le8

2021/09/20 10:05

ご回答ありがとうございました。Threadを使わずに関数を一つにして、ボタンをクリックしたときの動作に、 pyglet.clock.schedule_once(lambda _: pyglet.app.exit(), 3) pyglet.app.run() をそれぞれ追加したら、エラーなく音が鳴りました。 助かりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問