【问题标题】:Update PyQt progress from another thread running FTP download从另一个运行 FTP 下载的线程更新 PyQt 进度
【发布时间】:2019-08-22 10:17:28
【问题描述】:

我想从另一个类/线程(DownloadThread() 类)访问进度条(在 Ui_MainWindow() 类中)setMaximum()

我尝试让DownloadThread() 类继承自Ui_MainWindowDownloadThread(Ui_MainWindow)。但是当我尝试设置最大进度条值时:

Ui_MainWindow.progressBar.setMaximum(100)

我收到此错误:

AttributeError:类型对象“Ui_MainWindow”没有属性“progressBar”

我的代码:

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        # ...
        self.updateButton = QtGui.QPushButton(self.centralwidget)
        self.progressBar = QtGui.QProgressBar(self.centralwidget)
        self.updateStatusText = QtGui.QLabel(self.centralwidget)
        # ...
        self.updateButton.clicked.connect(self.download_file)
        # ...

    def download_file(self):
        self.thread = DownloadThread()
        self.thread.data_downloaded.connect(self.on_data_ready)
        self.thread.start()

    def on_data_ready(self, data):
        self.updateStatusText.setText(str(data))


class DownloadThread(QtCore.QThread, Ui_MainWindow):

    data_downloaded = QtCore.pyqtSignal(object)

    def run(self):
        self.data_downloaded.emit('Status: Connecting...')

        ftp = FTP('example.com')
        ftp.login(user='user', passwd='pass')

        ftp.cwd('/some_directory/')

        filename = '100MB.bin'
        totalsize = ftp.size(filename)
        print(totalsize)

        # SET THE MAXIMUM VALUE OF THE PROGRESS BAR
        Ui_MainWindow.progressBar.setMaximum(totalsize)          

        self.data_downloaded.emit('Status: Downloading...')

        global localfile
        with open(filename, 'wb') as localfile:
            ftp.retrbinary('RETR ' + filename, self.file_write)

        ftp.quit()
        localfile.close()

        self.data_downloaded.emit('Status: Updated!')

    def file_write(self, data):
        global localfile
        localfile.write(data)
        print(len(data))

【问题讨论】:

  • 我想它是您调用的线程类,因此您需要一个信号来执行此操作并从主窗口访问进度条
  • @ΕυάγγελοςΓρηγορόπουλος 我该如何做信号?
  • 这里是代码:hastebin.com/fequboleho.rb
  • Ui_MainWindow.progressBar.setMaximum(100) 应该是 self.progressBar.setMaximum(100)

标签: python ftp pyqt progress-bar ftplib


【解决方案1】:

直接的问题是Ui_MainWindow 是一个类,而不是该类的实例。您必须将“窗口”self 传递给DownloadThread。但这无论如何都不是正确的解决方案。您不能从另一个线程访问 PyQt 小部件。相反,使用您已经使用的相同技术来更新状态文本 (FTP download with text label showing the current status of the download)。

class Ui_MainWindow(object):
    def download_file(self):
        self.thread = DownloadThread()
        self.thread.data_downloaded.connect(self.on_data_ready)
        self.thread.data_progress.connect(self.on_progress_ready)
        self.progress_initialized = False
        self.thread.start()

    def on_progress_ready(self, data):
        # The first signal sets the maximum, the other signals increase a progress
        if self.progress_initialized:
            self.progressBar.setValue(self.progressBar.value() + int(data))
        else:
            self.progressBar.setMaximum(int(data))
            self.progress_initialized = True

class DownloadThread(QtCore.QThread):

    data_downloaded = QtCore.pyqtSignal(object)
    data_progress = QtCore.pyqtSignal(object)

    def run(self):
        self.data_downloaded.emit('Status: Connecting...')

        with FTP('example.com') as ftp:
            ftp.login(user='user', passwd='pass')

            ftp.cwd('/some_directory/')

            filename = '100MB.bin'
            totalsize = ftp.size(filename)
            print(totalsize)

            # The first signal sets the maximum
            self.data_progress.emit(str(totalsize))

            self.data_downloaded.emit('Status: Downloading...')

            with open(filename, 'wb') as self.localfile:
                ftp.retrbinary('RETR ' + filename, self.file_write)

        self.data_downloaded.emit('Status: Updated!')

    def file_write(self, data):
        self.localfile.write(data)
        # The other signals increase a progress
        self.data_progress.emit(str(len(data)))

对代码的其他更改:

  • global localfile 是一种不好的做法。请改用self.localfile
  • 不需要localfile.close()with 可以解决这个问题。
  • 同样ftp.quit() 应替换为with
  • DownloadThread 无需继承 Ui_MainWindow

【讨论】:

  • @Aspect Btw, global localfile 是一种不好的做法。请改用self.localfile。 + 不需要self.localfile.close()with 会处理这个问题。 + DownloadThread 不需要继承 Ui_MainWindow。 --- 我也在我的回答中更正了这一点。
【解决方案2】:

线程类:

from PyQt5 import QtCore, QtGui, QtWidgets, QtPrintSupport,QtWebEngineWidgets
from PyQt5.QtWidgets import QDialog,QWidget,QApplication, QInputDialog, QLineEdit, QFileDialog,QProgressDialog, QMainWindow, QFrame,QSplashScreen
from PyQt5.QtCore import QThread , pyqtSignal,Qt
from PyQt5.QtGui import QIcon,QPainter,QPixmap

class threaded_class(QThread):

    signal_to_send_at_progress_bar = pyqtSignal()
    def __init__(self,parent=None):
        QThread.__init__(self, parent=parent)
    def run(self):
        while self.isRunning:
            ##do the stuf you want here and when you want to change the progress bar
            self.signal_to_send_at_progress_bar.emit()

在您的主窗口中:

class mainProgram(QtWidgets.QMainWindow, Ui_MainWindow):                   #main window


    def __init__(self, parent=None):

        super(mainProgram, self).__init__(parent)
        self.setupUi(self)
        ###...........#####
        self.thread_class_in_main_window = threaded_class()
        self.thread_class_in_main_window .start()
        self.thread_db.signal_to_send_at_progress_bar.connect(progressBar.setMaximum(100))

您还可以使用信号发出字符串和数字。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-12
    • 2017-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多