PyQt5中局部实例化类的Slot方法未触发问题求助
问题根源:局部变量被垃圾回收导致信号槽失效
你猜的完全没错!问题就出在循环里的localPlay是局部变量,循环结束后被Python垃圾回收机制销毁了。
具体原因:
在你的循环代码里,每次创建的AudioPlayer实例localPlay是循环体内的局部变量。当循环执行完,这些实例没有被任何其他对象(比如你的Session实例)持有引用,Python的垃圾回收器就会把它们清理掉。虽然你把按钮的clicked信号连接到了localPlay.play,但一旦实例被销毁,这个信号槽连接就会自动失效,所以点击按钮时根本找不到对应的槽函数来执行,自然既没有打印信息也不会播放音频。
解决办法:给AudioPlayer实例保留一个持久引用
只需要在Session类里添加一个实例变量,用来存储所有AudioPlayer的实例,让它们能被Session对象持有引用,避免被垃圾回收。
修改后的完整代码如下:
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() # 新增:创建一个列表来保存AudioPlayer实例,避免被回收 self.audio_players = [] filenames = [r'C:\...\file1.mp3', r'C:\...\file2.mp3'] for filename in filenames: playButton = QPushButton('Play', self) localPlay = AudioPlayer(filename) # 把实例添加到列表里 self.audio_players.append(localPlay) playButton.clicked.connect(localPlay.play) self.vbox.addWidget(playButton) if __name__ == '__main__': app = QApplication(sys.argv) Session() sys.exit(app.exec_())
另一种可选方案:把实例绑定到按钮属性上
你也可以不用单独的列表,直接把AudioPlayer实例绑定到对应的按钮对象上,同样能保留引用:
# 循环内替换为: playButton = QPushButton('Play', self) localPlay = AudioPlayer(filename) # 绑定到按钮的自定义属性 playButton.audio_player = localPlay playButton.clicked.connect(localPlay.play) self.vbox.addWidget(playButton)
这两种方法都能解决问题,运行后点击按钮就能正常触发播放逻辑了。
内容的提问来源于stack exchange,提问作者pie3636
相关产品推荐
相关产品推荐

