简体   繁体   中英

python can't break while loop when play audio with pygame-change

I tried something new to fit the code. Now when I press ctrl + s the audio really stops but when my personal assistant plays music again in the same run, the music does not stop as for the first time:

import glob
import os
import keyboard

os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "hide"

import pygame
songs = glob.glob("C:\\Users\zivsi\Music\\*.mp3")
import random

song = random.choice(songs)

with open("song_choice.txt", "r") as file:
    read = file.read()

if (read == song):
    print("switch song")
    song = random.choice(songs)

song_name = song.replace("C:\\Users\zivsi\Music\\", "").replace(".mp3", "")
print("song: ", song_name)

pygame.mixer.init()

music = pygame.mixer.music.load(song)
pygame.mixer.music.play()

while (pygame.mixer_music.get_busy()):
    pygame.time.Clock().tick(10)
    keyboard.add_hotkey("ctrl + s", lambda: pygame.mixer_music.stop())

# if i will press ctrl + s, the music will stop but it's working only once`

You can't use break in a different scope, it has to be part of the loop suite itself (so nested inside a while or for statement). A lambda is a function, which is a different scope.

Because you want to break out of the loop asynchronously, you'll need some other way to communicate from the keyboard callback handler back to the main loop. In general computer engineering terms, you need some kind of synchronization primitive to synchronize between different things that are happening at the same time, concurrently.

That is to say, you want to set some kind of flag , one that you can check in your while loop, so while pygame.mixer_music.get_busy() and not keyboard_ctrl_s_flag: . You can do this with any global value, and that'd probably be safe:

keyboard_ctrl_s_flag = False  

def control_s_handler():
    """Called when the keyboard combination CTRL-S is pressed"""
    global keyboard_ctrl_s_flag
    keyboard_ctrl_s_flag = True

keyboard.add_hotkey("ctrl + s", control_s_handler)

then you can use that in your loop:

# reset the flag to false, in case it was already set to true before
keyboard_ctrl_s_flag = False  
while pygame.mixer_music.get_busy() and not keyboard_ctrl_s_flag:
    pygame.time.Clock().tick(10)

I say this probably is safe, because I'm not quite sure how PyGame is running its event handling loop. Given that you also used pygame.time.Clock().tick(10) in your loop makes me think that the event loop probably waits for your Python code to return control before doing other things.

The next time that the user then uses CTRL-S , the control_s_handler() callback is called, keyboard_ctrl_s_flag is set to True , and when control returns to the while loop (because pygame.time.Clock().tick(10) returned control to your Python code) the while loop exits even if pygame.mixer_music.get_busy() is still true.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM