永远不会调用作为本地实例化 class 方法的插槽
Slot as method of a locally instantiated class is never called
我有一个 mp3 文件列表,每当按下不同的按钮时,我都会尝试通过 pygame 播放这些文件(每个按钮一个文件)。由于这些文件的数量是可变的,我只是实现了一个 for 循环,并且我有一个 AudioPlayer
class 每次实例化如下:
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_())
我的问题很简单,按下按钮时文件不播放,消息也根本不打印;就像插槽永远不会被调用一样:
admin@home> python main2.py
Created C:\...\file1.mp3
Created C:\...\file2.mp3
admin@home>
如果我在循环之外手动播放文件,就像这样,它会起作用:
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()
如您所见,我确保AudioPlayer继承了QObject并调用了__init__
,所以我相信它应该可以接收信号。那么这里发生了什么?是局部变量问题吗?
问题是由于在循环中创建的 AudioPlayer
对象是局部变量,所以当它们完成 运行 构造函数时,它们会从内存中删除。有两种可能的解决方案,第一种是使它们成为 class 的属性,或者第二种是将它们传递给父级,因为它们继承自 QObject
,我将使用第二种方法:
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_())
我有一个 mp3 文件列表,每当按下不同的按钮时,我都会尝试通过 pygame 播放这些文件(每个按钮一个文件)。由于这些文件的数量是可变的,我只是实现了一个 for 循环,并且我有一个 AudioPlayer
class 每次实例化如下:
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_())
我的问题很简单,按下按钮时文件不播放,消息也根本不打印;就像插槽永远不会被调用一样:
admin@home> python main2.py
Created C:\...\file1.mp3
Created C:\...\file2.mp3
admin@home>
如果我在循环之外手动播放文件,就像这样,它会起作用:
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()
如您所见,我确保AudioPlayer继承了QObject并调用了__init__
,所以我相信它应该可以接收信号。那么这里发生了什么?是局部变量问题吗?
问题是由于在循环中创建的 AudioPlayer
对象是局部变量,所以当它们完成 运行 构造函数时,它们会从内存中删除。有两种可能的解决方案,第一种是使它们成为 class 的属性,或者第二种是将它们传递给父级,因为它们继承自 QObject
,我将使用第二种方法:
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_())