I have a list of mp3 files that I'm trying to play through pygame whenever different buttons are pressed (one file per button). Since there is a variable number of those files, I'm simply implementing a for loop, and I have an AudioPlayer
class that I instantiate each time as follows:
import sys, pygame
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class AudioPlayer(QObject):
def __init__(self, filename):
super().__init__()
self.filename = filename
print("Created " + filename)
def play(self):
print("Playing " + self.filename)
pygame.mixer.music.load(self.filename)
pygame.mixer.music.play()
class Session(QMainWindow):
def __init__(self):
super().__init__()
self.mainWid = QWidget(self)
self.vbox = QVBoxLayout()
self.mainWid.setLayout(self.vbox)
self.setCentralWidget(self.mainWid)
self.show()
pygame.mixer.init()
filenames = [r'C:\...\file1.mp3', r'C:\...\file2.mp3']
for filename in filenames:
playButton = QPushButton('Play', self)
localPlay = AudioPlayer(filename)
playButton.clicked.connect(localPlay.play)
self.vbox.addWidget(playButton)
if __name__ == '__main__':
app = QApplication(sys.argv)
Session()
sys.exit(app.exec_())
My problem is simply that the files do not play when I press the button, neither does the message get printed at all; it's like the slot never gets called:
admin@home> python main2.py
Created C:\...\file1.mp3
Created C:\...\file2.mp3
admin@home>
If I play the files manually outside of the loop, like this, it works:
class Session(QMainWindow):
def __init__(self):
# ...
filenames = [r'C:\...\file1.mp3', r'C:\...\file2.mp3']
pygame.mixer.music.load(filenames[0])
pygame.mixer.music.play()
As you can see, I made sure AudioPlayer inherited QObject and called __init__
, so I believe it should be able to receive signals. So what is going on here? Is it a local variable issue?
The problem is caused by the fact that the AudioPlayer
objects created in the loop are local variables, so when they finish running the constructor they are deleted from memory. There are 2 possible solutions, the first is to make them attributes of the class, or the second is to pass them a parent since they inherit from QObject
, I will use this second method:
class AudioPlayer(QObject):
def __init__(self, filename, parent=None):
super().__init__(parent=parent)
self.filename = filename
print("Created " + filename)
@pyqtSlot()
def play(self):
print("Playing " + self.filename)
pygame.mixer.music.load(self.filename)
pygame.mixer.music.play()
class Session(QMainWindow):
def __init__(self):
super().__init__()
self.mainWid = QWidget(self)
self.vbox = QVBoxLayout()
self.mainWid.setLayout(self.vbox)
self.setCentralWidget(self.mainWid)
self.show()
pygame.mixer.init()
filenames = [r'C:\...\file1.mp3', r'C:\...\file2.mp3']
for filename in filenames:
playButton = QPushButton('Play', self)
localPlay = AudioPlayer(filename, self)
playButton.clicked.connect(localPlay.play)
self.vbox.addWidget(playButton)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Session()
sys.exit(app.exec_())