python - PyQt 中程序退出后不会关闭

标签 python pyqt pygame pyqt5

所以,最近我尝试使用 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_())

提前致谢。

最佳答案

主要问题是 threading.Thread 仍在运行,因此当 QtApplication“关闭”时,程序仍然处于事件状态。

您确实应该避免使用 while 循环来检查当前位置,因为它会在每次循环循环时调用该值的请求,从而消耗大量不必要的 CPU 资源。
另外,每次循环时,您都会将 sliderMoved 信号连接到eek_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. 您确实应该考虑使用布局,或者确保窗口大小是固定的,否则用户将能够将其大小调整为小于界面的大小。

关于python - PyQt 中程序退出后不会关闭,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57373404/

相关文章:

python - 警告 :0 terminating async callback error in cv2

python - 使用 Python Paramiko 在不同的 SSH 服务器中并行运行多个命令

python - 如何复制QtableWidget的一行并插入到它下面的行?

python - PySide-PyQt : How to make set QTableWidget column width as proportion of the available space?

带有 VTK 的 Python 可执行文件... pyinstaller、py2exe、cx_freeze 等

python - 检测 pygame 中的用户事件

python - 无法弄清楚如何检查两个 Sprite 之间的掩码碰撞

python - sorl-thumbnail 不创建缩略图

python - pygame错误,没有设置视频模式

python - 数据框和 read_csv 函数 - Python