【问题标题】:Program Doesn't Close After Quitting It In PyQt程序在 PyQt 中退出后没有关闭
【发布时间】:2019-08-06 09:53:46
【问题描述】:

所以,最近我尝试使用 PyQt5、pygame 和 mutagen 制作音频播放器。该程序运行良好。但是当我播放歌曲并尝试退出程序时,程序停止响应,歌曲继续播放。但是当歌曲没有播放时,这不会发生,它可以正常工作。

代码如下:

from PyQt5 import QtWidgets, QtGui
from PyQt5.QtWidgets import QApplication, QMainWindow, QSlider
from PyQt5.QtGui import QColor
from PyQt5.QtCore import Qt
import sys
import pygame as pg
from mutagen.mp3 import MP3
import os
import threading

pg.init()

#33206

class window(QMainWindow):
    def __init__(self):
        super(window, self).__init__()
        self.setGeometry(425, 65, 400, 190)
        self.setWindowIcon(QtGui.QIcon("icon"))
        self.setWindowTitle("MultiMedia Player")

        # MenuBar
        file = QtWidgets.QAction("&Open Mp3", self)
        file.setShortcut("Ctrl + O")
        file.triggered.connect(self.open_mp3)

        # Quit
        quit = QtWidgets.QAction("&Quit", self)
        quit.setShortcut("Q")
        quit.triggered.connect(self.close_app)

        # Add Items

        items = QtWidgets.QAction("&Add Items", self)
        items.setShortcut("Ctrl + P")

        mainmenu = self.menuBar()
        filemenu = mainmenu.addMenu("&Open")
        filemenu.addAction(file)
        add_items = mainmenu.addMenu("&Add Items")
        add_items.addAction(items)
        filemenu.addAction(quit)

        self.flag = 0

        self.home()

    def home(self):

        # colors
        black = (13, 13, 13)
        light_black = (36, 36, 36)

        # Pause Button
        self.pause_btn = QtWidgets.QPushButton(self)
        self.pause_btn.setText("Pause")
        self.pause_btn.setShortcut("p")
        self.pause_btn.move(0, 120)
        self.pause_btn.clicked.connect(self.pause)

        # Play Button
        self.play_btn = QtWidgets.QPushButton(self)
        self.play_btn.setText("Play")
        self.play_btn.setShortcut("Space")
        self.play_btn.move(150, 120)
        self.play_btn.clicked.connect(self.play)

        # Stop Button
        self.stop_btn = QtWidgets.QPushButton(self)
        self.stop_btn.setText("Stop")
        self.stop_btn.setShortcut("s")
        self.stop_btn.move(300, 120)

        self.stop_btn.clicked.connect(self.stop)
        # color for the window

        color = QColor(70, 70, 70)

        # Volume_Up Button
        self.vup_btn = QtWidgets.QPushButton(self)
        self.vup_btn.setText("V(+)")
        self.vup_btn.setShortcut("+")
        self.vup_btn.move(300, 160)
        self.vup_btn.clicked.connect(self.volume_up)


        # Volume_Down Button
        self.vdown_btn = QtWidgets.QPushButton(self)
        self.vdown_btn.setText("V(-)")
        self.vdown_btn.setShortcut("-")
        self.vdown_btn.move(0, 160)
        self.vdown_btn.clicked.connect(self.volume_down)


        # Seek Slider

        self.slider = QSlider(Qt.Horizontal, self)
        self.slider.setGeometry(20, 75, 350, 20)

        # Volume Slider

        self.v_slider = QSlider(Qt.Horizontal, self)
        self.v_slider.setGeometry(120, 165, 160, 20)
        self.v_slider.setMinimum(0)
        self.v_slider.setMaximum(100)
        self.v_slider.setValue(70)
        self.volume_value = self.v_slider.value()
        self.v_slider.valueChanged.connect(self.slider_value_changed)
        print(self.v_slider.value() / 100)



    def msg(self, title, message):
        msg1 = QtWidgets.QMessageBox()
        msg1.setWindowIcon(QtGui.QIcon("icon"))
        msg1.setWindowTitle(title)
        msg1.setText(message)
        msg1.setStandardButtons(QtWidgets.QMessageBox.Ok)
        msg1.exec_()


    def open_mp3(self):
        name = QtWidgets.QFileDialog.getOpenFileName(self)

        format = os.path.splitext(name[0])
        if format[1] == ".mp3":
            self.audio = MP3(name[0])
            self.duration = self.audio.info.length//1
            self.min = int(self.duration // 60)
            self.sec = int(self.duration % 60)

            self.total_time = str(self.min) + ":" + str(self.sec)
            print(self.total_time)

            self.slider.setMaximum(self.duration)
            self.slider.setMinimum(0)
            time = []
            time.append(self.total_time)
            self.label = QtWidgets.QLabel(self)
            self.label.setText(self.total_time)
            self.label.setFont(QtGui.QFont("Arial", 9))
            self.label.adjustSize()
            self.label.move(373, 77)

            song = name[0]
            pg.mixer.music.load(song)
            pg.mixer.music.play(1)
            pg.mixer.music.set_volume(self.v_slider.value()/100)

            self.label = QtWidgets.QLabel(self)
            self.label.setText(song)
            self.label.setFont(QtGui.QFont("Arial", 15))
            self.label.adjustSize()
            self.label.move(0, 36)
            self.label.show()
            threading_1 = threading.Thread(target=self.cur_time).start()

        else:
            self.msg("Invalid Format", "Choose A .Mp3 File Only!")

    volume_level = pg.mixer.music.get_volume()
    print(volume_level)

    def cur_time(self):

        true = 1
        while true == 1:
            if self.flag == 0:
                self.m_time = pg.mixer.music.get_pos()
                self.mm_time = self.m_time * 0.001
                self.s_time = self.mm_time // 1
                self.slider.setValue(self.s_time)
                print(self.s_time)
                self.slider.sliderMoved.connect(self.seek_changed)
            if self.s_time == -1:
                self.slider.setValue(0)
                true = 2

            if self.flag == 1:
                print(self.s_time)

    def seek_changed(self):
        print(self.slider.value())
        pg.mixer.music.set_pos(self.slider.value())

    def slider_value_changed(self):
        self.volume_value = self.v_slider.value()
        pg.mixer.music.set_volume(self.v_slider.value()/100)

    def volume_up(self):
        self.volume_value = self.volume_value + 10
        self.v_slider.setValue(self.volume_value)

        if self.volume_value >= 100:
            self.volume_value = 100


        pg.mixer.music.set_volume(self.v_slider.value() / 100)
        print(self.v_slider.value() / 100)


    def volume_down(self):
        self.volume_value = self.volume_value - 10
        self.v_slider.setValue(self.volume_value)

        if self.volume_value <= 0:
            self.volume_value = 0
        pg.mixer.music.set_volume(self.v_slider.value() / 100)
        print(self.v_slider.value() / 100)


    def pause(self):
        pg.mixer.music.pause()
        self.flag = 1

    def stop(self):
        pg.mixer.music.stop()
        self.flag = -1

    def play(self):

        pg.mixer.music.unpause()
        self.flag = 0


    def close_app(self):
        choice = QtWidgets.QMessageBox.question(
            self, "QUIT", "You Sure You Wanna Quit?", QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
        if choice == QtWidgets.QMessageBox.Yes:
            sys.exit()
        else:
            pass




    def items(self):
        layout = QtWidgets.QVBoxLayout(self)
        song_name = QtWidgets.QFileDialog.getOpenFileName(self)

        widget = QtWidgets.QListWidget()
        widget.setAlternatingRowColors(True)
        widget.setDragDropMode(
            QtWidgets.QAbstractItemView.InternalMove)

        widget.addItems([str(i) for i in range(1, 6)])
        layout.addWidget(widget)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = window()
    win.show()
    sys.exit(app.exec_())

提前致谢。

【问题讨论】:

    标签: python pyqt pygame pyqt5


    【解决方案1】:

    主要问题是您仍在运行 threading.Thread,因此当 QtApplication “关闭”时,程序仍然存在。

    您确实应该避免使用 while 循环来检查当前位置,因为它会在每次循环循环时调用请求该值,从而消耗大量不必要的 CPU 资源。
    此外,每次循环循环时,您都将 sliderMoved 信号连接到 seek_changed,这是

    改用 QTimer,它会更新光标位置而不会使进程过载:

        # create a timer in the window __init__
        self.cursor_updater = QtCore.QTimer(interval=100, timeout=self.cur_time)
    
        #...
        def cur_time(self):
            # ignore the update if the user is seeking
            if self.slider.isSliderDown():
                return
            self.slider.setValue(pg.mixer.music.get_pos() * .001)
    

    然后,您只需在每次音乐开始(或取消暂停)时启动计时器,并在您停止或暂停时停止。


    也就是说,您的代码还有其他问题。

    1. pygame 和 Qt 运行它们自己的事件循环,因此您不能通过sys.exit() 或它们自己的quit() 函数轻松优雅地退出,因为它们中的一个或两个都可能只会挂在自己的循环中而无法真正退出,保持进程运行(循环几乎什么都不做)并消耗大量资源。我不是使用 pygame PyQt 的专家,但据我所知,您可以致电 os._exit(0)
    2. 应该注意窗口closeEvent(),因为如果用户只是关闭窗口而不退出,则不会出现任何确认对话框,也不会调用上述退出过程。
    3. pygame.mixer.music.get_pos()“只代表音乐播放了多长时间;它不考虑任何起始位置偏移”。因此,您需要在使用 set_pos() 时跟踪位置并相应地计算实际值。
    4. 您确实应该考虑使用布局,或者确保窗口大小是固定的,否则用户将能够将其调整为比界面更小的大小。

    【讨论】:

    • 从不知道我的代码有这么多问题,谢谢,我会尽力解决所有问题。刚写完所有代码就想用布局了,当时就懒得修了。
    猜你喜欢
    • 1970-01-01
    • 2013-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-12
    相关资源
    最近更新 更多