在PyQt中退出该程序后无法关闭

时间:2019-08-06 09:53:46

标签: 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_())

谢谢。

1 个答案:

答案 0 :(得分:2)

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

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