Search code examples
pythonpython-3.xftppyqtftplib

FTP download with text label showing the current status of the download


I made a GUI in which after I click "Download" button the program will download files from FTP server. When doing that I want the label to update e.g: "Connecting..." -> "Downloading..." -> "Downloaded!" I tried doing it with threading module but it seems to not work:

def updater(self):
    self.updateStatusText.setText("Status: Connecting...")

    thread = threading.Thread(target=self.download)
    thread.start()

    while thread.isAlive():
        self.updateStatusText.setText("Status: Still Downloading...")


def download(self):
    ftp = FTP('testdomain.com')
    ftp.login(user='username', passwd='password')

    ftp.cwd('/main_directory/')

    filename = 'testfile.bin'

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

    ftp.quit()
    localfile.close()

It just downloads the file and doesn't change the text label at all. Do I have to use QThread here? I also tried using asyncio but awaiting self.updateStatusText.setText("Connecting...") seems to return None and I get TypeError...


Solution

  • The following code should do:

    class DownloadThread(QtCore.QThread):
    
        data_downloaded = QtCore.pyqtSignal(object)
    
        def run(self):
            self.data_downloaded.emit('Connecting...')
    
            ftp = FTP('example.com')
            ftp.login(user='user', passwd='password')
    
            ftp.cwd('/main_directory/')
    
            self.data_downloaded.emit('Downloading...')
    
            filename = 'testfile.bin'
            with open(filename, 'wb') as localfile:
                ftp.retrbinary('RETR ' + filename, localfile.write)
    
            ftp.quit()
    
            self.data_downloaded.emit('Done')
    
    class MainWindow(QtGui.QWidget):
        def __init__(self):
            super(MainWindow, self).__init__()
            self.label = QtGui.QLabel
            self.button = QtGui.QPushButton("Start")
            self.button.clicked.connect(self.start_download)
            layout = QtGui.QVBoxLayout()
            layout.addWidget(self.button)
            layout.addWidget(self.label)
            self.setLayout(layout)
    
        def start_download(self):
            self.thread = DownloadThread()
            self.thread.data_downloaded.connect(self.on_data_ready)
            self.thread.start()
    
        def on_data_ready(self, data):
            self.label.setText(unicode(data))
    

    Based on: Updating GUI elements in MultiThreaded PyQT.

    Your followup question: Update PyQt progress from another thread running FTP download