pyqt5:qprogressbar不会更新

发布于 2025-01-22 07:30:31 字数 4335 浏览 3 评论 0原文

我有一个应用程序,其中其中一个功能是使用Pytube下载YouTube视频。除了下载进度以更新Qprogressbar外,一切都很好。请参阅下面的代码:

import pytube

import PyQt5.QtWidgets as QtWidgets
import PyQt5.QtCore as QtCore


class Worker(QtCore.QObject):
    finished = QtCore.pyqtSignal()
    progress = QtCore.pyqtSignal(str, int, int)

    def __init__(self, url, save_path, fname):
        super(Worker, self).__init__()
        self.url = url
        self.save_path = save_path
        self.fname = fname
        self.perc_dl = 0

        self.download_video()

    def run(self):
        if self.perc_dl < 100:
            self.progress.emit('Downloading: {}%'.format(str(self.perc_dl)), int(self.perc_dl), 100)
            print(self.perc_dl)

        else:
            self.progress.emit('Done!', 100, 100)
            self.finished.emit()

    def download_video(self):
        yt = pytube.YouTube(self.url, on_progress_callback=self.progress_function)
        stream = yt.streams.filter(progressive=True, file_extension='mp4').get_highest_resolution()
        stream.download(output_path=self.save_path, filename=self.fname)

    def progress_function(self, stream, chunk, bytes_remaining):
        curr = stream.filesize - bytes_remaining
        per_downloaded = round((curr / stream.filesize) * 100, 1)
        self.perc_dl = per_downloaded
        self.run()


class DownloadFromYT(QtWidgets.QDialog):
    def __init__(self, url, save_path, fname):
        super(DownloadFromYT, self).__init__()
        self.url = url
        self.save_path = save_path
        self.fname = fname

        self.vLayoutMaster = QtWidgets.QVBoxLayout()
        self.hLayout = QtWidgets.QHBoxLayout()
        self.hLayout.setAlignment(QtCore.Qt.AlignRight)

        self.label = QtWidgets.QLabel()
        self.label.setText('Downloading video')

        self.pBar = QtWidgets.QProgressBar()
        self.pBar.setInvertedAppearance(True)
        self.pBar.setTextVisible(True)
        self.pBar.setFixedWidth(200)
        self.pBar.setAlignment(QtCore.Qt.AlignCenter)
        self.pBar.setMaximum(100)
        self.pBar.setFormat('Downloading: ')

        self.noButton = QtWidgets.QPushButton('No')
        self.noButton.setFixedWidth(50)
        self.noButton.hide()
        self.yesButton = QtWidgets.QPushButton('Yes')
        self.yesButton.setFixedWidth(50)
        self.yesButton.hide()

        self.vLayoutMaster.addWidget(self.label)
        self.vLayoutMaster.addSpacing(10)
        self.vLayoutMaster.addWidget(self.pBar)
        self.vLayoutMaster.addSpacing(20)
        self.hLayout.addWidget(self.noButton)
        self.hLayout.addWidget(self.yesButton)
        self.vLayoutMaster.addLayout(self.hLayout)

        # Signals / slots
        self.noButton.clicked.connect(self.reject)
        self.yesButton.clicked.connect(self.accept)

        # Widget
        self.setLayout(self.vLayoutMaster)
        self.setWindowTitle('Downloading')
        self.setFixedSize(250, 100)
        self.show()

        # Init download
        self.run_thread(url, save_path, fname)

    def run_thread(self, url, save_path, fname):
        self.thrd = QtCore.QThread()
        self.worker = Worker(url, save_path, fname)
        self.worker.moveToThread(self.thrd)

        self.thrd.start()
        self.thrd.started.connect(self.worker.run)
        self.worker.finished.connect(self.thrd.quit)
        self.worker.finished.connect(self.worker.deleteLater)
        self.worker.progress.connect(self.show_progress)
        self.thrd.finished.connect(self.thrd.deleteLater)

    def show_progress(self, label, n, total):
        self.pBar.setFormat(label)
        self.pBar.setMaximum(total)
        self.pBar.setValue(n)
        QtCore.QCoreApplication.processEvents()

        if label == 'Done!':
            self.thrd.quit()
            self.noButton.show()
            self.yesButton.show()
            self.label.setText('Video has been downloaded. Would you like to set the chosen\n'
                               'file path as the "Local file" path?')

我在应用程序的其他部分中使用了此基本结构来显示和更新进度栏,没有任何问题,但是由于某种原因,self.pbar当<<<代码>进度信号是从worker类发出的。如您所见,我在运行方法中有一个print()语句,以检查代码实际上是否输入该,如果 block block和定期进行。将下载进度打印到控制台,这是。该应用程序完成运行后的应用程序会更新,因此我将获得最终的,完全填充的进度栏,但是在开始和结束之间,进度栏并未按预期进行更新。

任何帮助将不胜感激!

I have an application where one of its functions is to use pytube to download YouTube videos. Everything works perfectly except for updating the QProgressBar with the download progress. Please see below code:

import pytube

import PyQt5.QtWidgets as QtWidgets
import PyQt5.QtCore as QtCore


class Worker(QtCore.QObject):
    finished = QtCore.pyqtSignal()
    progress = QtCore.pyqtSignal(str, int, int)

    def __init__(self, url, save_path, fname):
        super(Worker, self).__init__()
        self.url = url
        self.save_path = save_path
        self.fname = fname
        self.perc_dl = 0

        self.download_video()

    def run(self):
        if self.perc_dl < 100:
            self.progress.emit('Downloading: {}%'.format(str(self.perc_dl)), int(self.perc_dl), 100)
            print(self.perc_dl)

        else:
            self.progress.emit('Done!', 100, 100)
            self.finished.emit()

    def download_video(self):
        yt = pytube.YouTube(self.url, on_progress_callback=self.progress_function)
        stream = yt.streams.filter(progressive=True, file_extension='mp4').get_highest_resolution()
        stream.download(output_path=self.save_path, filename=self.fname)

    def progress_function(self, stream, chunk, bytes_remaining):
        curr = stream.filesize - bytes_remaining
        per_downloaded = round((curr / stream.filesize) * 100, 1)
        self.perc_dl = per_downloaded
        self.run()


class DownloadFromYT(QtWidgets.QDialog):
    def __init__(self, url, save_path, fname):
        super(DownloadFromYT, self).__init__()
        self.url = url
        self.save_path = save_path
        self.fname = fname

        self.vLayoutMaster = QtWidgets.QVBoxLayout()
        self.hLayout = QtWidgets.QHBoxLayout()
        self.hLayout.setAlignment(QtCore.Qt.AlignRight)

        self.label = QtWidgets.QLabel()
        self.label.setText('Downloading video')

        self.pBar = QtWidgets.QProgressBar()
        self.pBar.setInvertedAppearance(True)
        self.pBar.setTextVisible(True)
        self.pBar.setFixedWidth(200)
        self.pBar.setAlignment(QtCore.Qt.AlignCenter)
        self.pBar.setMaximum(100)
        self.pBar.setFormat('Downloading: ')

        self.noButton = QtWidgets.QPushButton('No')
        self.noButton.setFixedWidth(50)
        self.noButton.hide()
        self.yesButton = QtWidgets.QPushButton('Yes')
        self.yesButton.setFixedWidth(50)
        self.yesButton.hide()

        self.vLayoutMaster.addWidget(self.label)
        self.vLayoutMaster.addSpacing(10)
        self.vLayoutMaster.addWidget(self.pBar)
        self.vLayoutMaster.addSpacing(20)
        self.hLayout.addWidget(self.noButton)
        self.hLayout.addWidget(self.yesButton)
        self.vLayoutMaster.addLayout(self.hLayout)

        # Signals / slots
        self.noButton.clicked.connect(self.reject)
        self.yesButton.clicked.connect(self.accept)

        # Widget
        self.setLayout(self.vLayoutMaster)
        self.setWindowTitle('Downloading')
        self.setFixedSize(250, 100)
        self.show()

        # Init download
        self.run_thread(url, save_path, fname)

    def run_thread(self, url, save_path, fname):
        self.thrd = QtCore.QThread()
        self.worker = Worker(url, save_path, fname)
        self.worker.moveToThread(self.thrd)

        self.thrd.start()
        self.thrd.started.connect(self.worker.run)
        self.worker.finished.connect(self.thrd.quit)
        self.worker.finished.connect(self.worker.deleteLater)
        self.worker.progress.connect(self.show_progress)
        self.thrd.finished.connect(self.thrd.deleteLater)

    def show_progress(self, label, n, total):
        self.pBar.setFormat(label)
        self.pBar.setMaximum(total)
        self.pBar.setValue(n)
        QtCore.QCoreApplication.processEvents()

        if label == 'Done!':
            self.thrd.quit()
            self.noButton.show()
            self.yesButton.show()
            self.label.setText('Video has been downloaded. Would you like to set the chosen\n'
                               'file path as the "Local file" path?')

I have used this basic structure in other parts of my application to display and update a progress bar with no issues, however for some reason here, self.pBar refuses to update when the progress signal is emitted from the Worker class. As you can see, I have a print() statement in the run method to check that the code is actually entering that if block and periodically printing out the download progress to the console, which it is. The application updates when the thread has finished running, so I get the final, completely filled progress bar, but in between the start and end the progress bar does not update as expected.

Any help would be greatly appreciated!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

允世 2025-01-29 07:30:31

问题似乎是,尽管您努力正确地将所有这些线程工具组件连接起来,但您仍在主(UI)线程中运行self.download_video()。因此,它阻止了UI的刷新。如果要在辅助线程中运行,则必须在worker.run()函数中启动它,而不是worker构造函数。如果正确连接所有线程,则无需调用ProcessEvents()以刷新UI。

如果不确定下载功能运行的线程,请在打印功能中打印线程ID,然后将其与主UI线程的线程ID进行比较。看看 https://doc.qt.io/qt.io/qt-5/ qthread.html#CurrentThread

The problem seems to be that despite all your effort to wire up all that thread-worker components correctly, you are still running self.download_video() in the main (UI) thread. And therefore it is blocking refreshing of the UI. If you want to run in in the secondary thread, you must start it in Worker.run() function and not in the Worker constructor. If you wire up all threading correctly, then you should not need to call processEvents() at all to refresh UI.

If you are unsure about the thread in which the download function runs, print the thread ID in your print function and compare it to thread id of the main UI thread. Have a look at https://doc.qt.io/qt-5/qthread.html#currentThread

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文