问题
I want to access progress bar's (which is in the Ui_MainWindow() class) setMaximum() from another class/thread (DownloadThread() class).
I tried making DownloadThread() class inherit from Ui_MainWindow:
DownloadThread(Ui_MainWindow). But when I try to set the maximum progress bar value:
Ui_MainWindow.progressBar.setMaximum(100)
I get this error:
AttributeError: type object 'Ui_MainWindow' has no attribute 'progressBar'
My code:
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))
回答1:
The immediate problem is that Ui_MainWindow is a class, not an instance of the class. You would have to pass your "window" self to the DownloadThread. But that's not the right solution anyway. You cannot access PyQt widgets from another thread. Instead, use the same technique as you already do, to update the status text (FTP download with text label showing the current status of the download).
The following code shows the first step. But you will also have to pass the actual progress the same way. But you didn't show us your file_write, so I cannot post a complete solution yet.
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)))
Other changes to your code:
global localfileis a bad practice. Useself.localfileinstead.- There's no need for
localfile.close(),withtakes care of that. - Similarly
ftp.quit()should be replaced withwith. - There's no need for
DownloadThreadto inherit fromUi_MainWindow.
回答2:
the thread class:
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()
in your main window:
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))
You can also emit string and number with signals.
来源:https://stackoverflow.com/questions/57607072/update-pyqt-progress-from-another-thread-running-ftp-download