首页 > 解决方案 > Program Doesn't Close After Quitting It In PyQt

问题描述

So, Recently I was trying to make an audio player using PyQt5, pygame, and mutagen. The program works pretty fine. But when I'm playing a song and try to quit the program, the program stops responding and the song continues to play. But this doesn't happen when a song is not playing, it works fine then.

Here is the Code:

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_())

Thanks In Advance.

标签: pythonpyqtpygamepyqt5

解决方案


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

推荐阅读