Прогресбар загрузки файла с FTP-сервера, на Pyqt5

Подскажите как сделать прогрессбар загрузки на FTP-сервер на pyqt5.

import sys
import ftplib
import easygui 
import pyperclip
import os
import time
from PyQt5 import Qt
from PyQt5 import QtCore, QtGui, QtWidgets, Qt                              
from PyQt5.QtWidgets import QWidget, QGridLayout, QPushButton, QGraphicsOpacityEffect
from PyQt5.QtWidgets import QMainWindow, QAction, qApp, QApplication, QMenuBar, qApp, QGraphicsTextItem
from PyQt5.QtWidgets import QFileSystemModel, QHBoxLayout, QShortcut, QInputDialog, QToolBar
from PyQt5.QtWidgets import QTreeWidgetItem, QVBoxLayout, QMenu, QSplitter, QLineEdit, QLabel
from PyQt5.QtCore import QUrl, QRect, QFileInfo, Qt, QSize, QDir
from PyQt5.QtGui import QIcon, QKeySequence, QImage



class App(QMainWindow, QtWidgets.QGraphicsWidget):
    def __init__(self):
        super().__init__()

        self.splitter = QSplitter(Qt.Horizontal)

        self.hbox = QHBoxLayout()
        self.hbox.addWidget(self.splitter)
        self.ftp_log = []

        central_widget = QWidget()
        central_widget.setLayout(self.hbox)
        self.setCentralWidget(central_widget)

        self.columns = ['Name', 'Size']

        self.tool2 = QToolBar('tools')
        self.font = QtGui.QFont('White Rabbit')

        self.file = self.menuBar().addMenu('&File')
        self.exitActi = QAction(QIcon('cross-exit.ico'), '&Exit', self)
        self.exitActi.setShortcut('Ctrl+Q')
        self.exitActi.setStatusTip('Exit application')
        self.exitActi.triggered.connect(self.close)
        self.file.addAction(self.exitActi)

        self.server = self.menuBar().addMenu('Server')
        self.connectAction = QAction(QIcon('cross-exit.ico'), 'Connect server', self)
        self.connectAction.setStatusTip('Connect server')
        self.connectAction.triggered.connect(self.enter_FTP_server)
        self.connectAction.triggered.connect(self.ftp_lst)
        self.server.addAction(self.connectAction)

        self.disconnectAction = QAction(QIcon('cross-exit.ico'), 'Disconnect server', self)
        self.disconnectAction.setStatusTip('Disconnect server')
        self.disconnectAction.triggered.connect(self.disconnect_FTP_server)
        self.server.addAction(self.disconnectAction)

        self.updateAction = QAction(QIcon('cross-exit.ico'), 'Update list file', self)
        self.updateShortcut = QShortcut(QKeySequence("F5"), self)
        self.updateShortcut.activated.connect(self.ftp_lst)
        self.updateAction.setStatusTip('Update list file')
        self.updateAction.triggered.connect(self.ftp_lst)
        self.server.addAction(self.updateAction)

        self.DisconnectActiontool = QAction(QIcon('c:/Users/User/Desktop/FTP/disconnect.ico'), 'Disconnect')
        self.DisconnectActiontool.setShortcut('Ctrl+Q')
        self.DisconnectActiontool.triggered.connect(self.disconnect_FTP_server)

        self.refreshActiontool = QAction(QIcon('c:/Users/User/Desktop/FTP/refresh.png'), 'Refresh')
        self.refreshActiontool.setShortcut('F5')
        self.refreshActiontool.triggered.connect(self.ftp_lst)

        self.newfoldertool = QAction(QIcon('c:/Users/User/Desktop/FTP/kisspng-computer-icons-directory-font-folders-5acb4f1fbf1957.7771232615232735037828.jpg'), 'Refresh')
        self.newfoldertool.setShortcut('Ctrl+N+F')
        self.newfoldertool.triggered.connect(self.newfolder)

        self.cancelActiontool = QAction(QIcon('c:/Users/User/Desktop/FTP/cancel.png'), 'Cancel Download')
        self.cancelActiontool.setShortcut('Ctrl+Z')
        self.cancelActiontool.triggered.connect(self.abort)

        self.reconnectActiontool = QAction(QIcon('c:/Users/User/Desktop/FTP/reconnect.png'), 'Rеconnеct to sеrvеr')
        self.reconnectActiontool.setShortcut('Ctrl+L')
        self.reconnectActiontool.triggered.connect(self.enter_FTP_server)

        self.FolderbackActiontool = QAction(QIcon('c:/Users/User/Desktop/FTP/folderback.png'), 'Рrevious fоlder')
        self.FolderbackActiontool.triggered.connect(self.folderback)

        self.tool = self.addToolBar('Tools')
        self.tool.setIconSize(QSize(32, 32))
        self.tool.addAction(self.refreshActiontool)
        self.tool.addAction(self.DisconnectActiontool)
        self.tool.addAction(self.newfoldertool)
        self.tool.addAction(self.cancelActiontool)
        self.tool.addAction(self.reconnectActiontool)
        self.tool.addAction(self.FolderbackActiontool)


        self.tool2 = self.addToolBar('Tools connection')
        self.addressEdit = QLineEdit()
        self.loginEdit = QLineEdit()
        self.passwordEdit = QLineEdit()
        self.address = QLabel('IP address    ')
        self.login = QLabel(' Login    ')
        self.password = QLabel(' Password    ')
        self.dfgh = QLabel('  ')

        self.address.setFont(QtGui.QFont('SansSerif', 10))
        self.login.setFont(QtGui.QFont('SansSerif', 10))
        self.password.setFont(QtGui.QFont('SansSerif', 10))

        self.buttonquickconnection = QPushButton('quick connection')
        self.buttonquickconnection.clicked.connect(self.quickconnect)

        self.tool2.addWidget(self.address)
        self.tool2.addWidget(self.addressEdit)
        self.tool2.addWidget(self.login)
        self.tool2.addWidget(self.loginEdit)
        self.tool2.addWidget(self.password)
        self.tool2.addWidget(self.passwordEdit)
        self.tool2.addWidget(self.dfgh)
        self.tool2.addWidget(self.buttonquickconnection)

        self.FTP_tree = QtWidgets.QTreeWidget()
        self.FTP_tree.setHeaderLabels(self.columns)
        self.FTP_tree.setDisabled(True)
        self.FTP_tree.itemDoubleClicked.connect(self.downloading_from_server)
        self.splitter.addWidget(self.FTP_tree)

        self.model = QFileSystemModel(self)
        self.model.setRootPath('')
        self.tree = QtWidgets.QTreeView()
        self.tree.setModel(self.model)
        self.tree.setAnimated(False)
        self.tree.setIndentation(20)
        self.tree.setSortingEnabled(True)

        self.tree.clicked.connect(self.on_treeView_clicked)
        self.tree.clicked.connect(self.uploading_files_to_server)
        self.splitter.addWidget(self.tree)


    def quickconnect(self):
        print(self.addressEdit, self.loginEdit, self.passwordEdit)
        self.ftp = ftplib.FTP(self.addressEdit.text(), self.loginEdit.text(), self.passwordEdit.text())
        self.ftp.encoding = 'utf-8'
        self.ftp.set_pasv(False)
        self.ftp_lst()

    @QtCore.pyqtSlot(QtCore.QModelIndex)
    def on_treeView_clicked(self, index):
        indexItem = self.model.index(index.row(), 0, index.parent())
        self.filePath = self.model.filePath(indexItem)
        if QFileInfo(self.filePath).completeSuffix() != '':
            return self.filePath
        else: 
            pass

    def abort(self):
        self.ftp.abort()

    def disconnect_FTP_server(self):
        self.ftp.close()
        self.FTP_tree.clear()
        self.FTP_tree.setHeaderLabels(self.columns)
        self.FTP_tree.setDisabled(True)

    def folderback(self):
        self.ftp.cwd(self.dwc())
        self.ftp_lst()

    def word_getWelcome(self):
        str1 = self.ftp.getwelcome()
        self.words = str1.split()

    def enter_FTP_server(self):
        if self.ftp_log == None:
            self.ftp = ftplib.FTP('192.168.0.1' ,'Artem' ,'1204')
            self.ftp.encoding = 'utf-8'
            self.ftp.set_pasv(False)
            self.ftp_lst()
        else:
            msg = "Введите информацию о сервере"
            fieldNames = ["IP Сервера", "Логин", "Пароль"]
            title = 'FTP' 
            self.ftp_log = easygui.multpasswordbox(msg, title, fieldNames)
            self.ftp = ftplib.FTP('192.168.0.1' ,'Artem' ,'1204')
            self.ftp.encoding = 'utf-8'
            self.ftp.set_pasv(False)
            self.ftp_lst()

    def ftp_lst(self):
        self.FTP_tree.clear()
        self.FTP_tree.setHeaderLabels(self.columns)
        self.FTP_tree.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.FTP_tree.customContextMenuRequested.connect(self.openMenu)
        self.FTP_tree.setDisabled(False)
        self.FTP_item1 = QTreeWidgetItem(self.FTP_tree, ['..'])
        self.FTP_item1.setIcon(0, QIcon('c:/Users/User/Desktop/FTP/folderback.png'))
        self.nlst = self.ftp.nlst()
        self.nlst_len = len(self.nlst)
        self.FTP_item1.setFont(0, QtGui.QFont('Segoe UI', 10))
        for i in self.nlst:
            j = []
            j.append(i)    
            j.append(str(self.ftp.size(i)))
            self.FTP_item1 = QTreeWidgetItem(self.FTP_tree, j)
            self.FTP_item1.setFont(0, QtGui.QFont('Segoe UI', 9))
            self.FTP_item1.setFont(1, QtGui.QFont('Segoe UI', 9))
            b = j[0]
            c = QUrl(b).fileName()
            expansion = QFileInfo(c).completeSuffix()
            if expansion == '':        
                self.FTP_item1.setIcon(0, QIcon('c:/Users/User/Desktop/FTP/file/folder.ico'))
            elif expansion == 'exe':        
                self.FTP_item1.setIcon(0, QIcon('c:/Users/User/Desktop/FTP/file/IconGroup15.ico'))
            elif expansion == 'txt':        
                self.FTP_item1.setIcon(0, QIcon('c:/Users/User/Desktop/FTP/file/IconGroup19.ico'))
            elif expansion == 'py':
                self.FTP_item1.setIcon(0, QIcon('c:/Users/User/Desktop/FTP/file/pythonlogo.png'))
            elif expansion == 'pdf':
                self.FTP_item1.setIcon(0, QIcon('c:/Users/User/Desktop/FTP/file/pdf.png'))
            elif expansion == 'torrent':
                self.FTP_item1.setIcon(0, QIcon('c:/Users/User/Desktop/FTP/file/torrent.png'))
            elif expansion == 'png':       
                 self.FTP_item1.setIcon(0, QIcon('c:/Users/User/Desktop/FTP/file/IconGroup71.ico'))
            elif expansion == 'mp3':        
                 self.FTP_item1.setIcon(0, QIcon('c:/Users/User/Desktop/FTP/file/IconGroup131.ico'))
            elif expansion == 'mp4' or expansion == 'avi' or expansion == 'mkd':        
                self.FTP_item1.setIcon(0, QIcon('c:/Users/User/Desktop/FTP/file/IconGroup23.ico'))
            elif expansion == 'docx' or expansion == 'doc':        
                self.FTP_item1.setIcon(0, QIcon('c:/Users/User/Desktop/FTP/file/word.png'))
            elif expansion == 'xls' or expansion == 'xlsx':        
                self.FTP_item1.setIcon(0, QIcon('c:/Users/User/Desktop/FTP/file/excel.png'))
            elif expansion == 'pptx' and expansion == 'ppt':        
                self.FTP_item1.setIcon(0, QIcon('c:/Users/User/Desktop/FTP/file/PowerPoint.png'))
            else:
                self.FTP_item1.setIcon(0, QIcon('c:/Users/User/Desktop/FTP/file/file.ico'))


            self.FTP_item1.setFlags(self.FTP_item1.flags() | QtCore.Qt.ItemIsEditable)
        # self.splitter.addWidget(self.FTP_tree)
        self.file_lst = self.ftp.nlst()
        self.len_file_lst = len(self.nlst)

        # self.FTP_tree = QtWidgets.QTreeWidget()

    def openMenu(self, position):
        self.position = position
        self.menu = QtWidgets.QMenu()

        self.openfolder_or_downloadfile = QtWidgets.QAction(QIcon('c:/Users/User/Desktop/FTP/folderback.png'), 'opening folder or downloading file', self.menu)
        self.openfolder_or_downloadfile.triggered.connect(self.downloading_from_server_for_toolbar)
        self.menu.addAction(self.openfolder_or_downloadfile)
        self.menu.addSeparator()

        self.new_folder = QtWidgets.QAction(QIcon('c:/Users/User/Desktop/FTP/kisspng-computer-icons-directory-font-folders-5acb4f1fbf1957.7771232615232735037828.jpg'), 
                                            'New folder', self.menu)
        self.menu.addAction(self.new_folder)
        self.new_folder.triggered.connect(self.newfolder)

        self.new_folder_open = QtWidgets.QAction('Create a folder and open', self.menu)
        self.menu.addAction(self.new_folder_open)
        self.new_folder_open.triggered.connect(self.newfolderopen)

        self.update = QtWidgets.QAction(QIcon('c:/Users/User/Desktop/FTP/refresh.png'), 'Update', self.menu)
        self.update.triggered.connect(self.ftp_lst)
        self.menu.addAction(self.update)
        self.menu.addSeparator()

        self.delete = QtWidgets.QAction(QIcon('c:/Users/User/Desktop/FTP/file/IconGroup55.ico'), 'Delete', self.menu)
        self.menu.addAction(self.delete)
        self.delete.triggered.connect(self.delete_file)

        self.rename = QtWidgets.QAction('Rename', self.menu)
        self.rename.triggered.connect(self.rename_file)
        self.menu.addAction(self.rename)

        self.copy_to_clipboard = QtWidgets.QAction('Copy to clipboard', self.menu)
        self.menu.addAction(self.copy_to_clipboard)
        self.copy_to_clipboard.triggered.connect(self.copytoclipboard)







        if self.FTP_tree.itemAt(self.position) != None:
            self.menu.exec_(self.FTP_tree.viewport().mapToGlobal(self.position))
        else:
            pass

    def copytoclipboard(self):
        a = f'ftp://{self.ftp_log[0]}{self.ftp.pwd()}/{self.FTP_tree.currentItem().text(0)}'
        pyperclip.copy(a)

    def newfolderopen(self):
        text, ok = QInputDialog.getText(self, 'FTPZ',
            'Enter a new folder name:')
        if ok:
            self.ftp.mkd(text)
            b = f'{self.ftp.pwd()}/{text}'
            self.ftp.cwd(b)  
        self.ftp_lst()

    def newfolder(self):
        text, ok = QInputDialog.getText(self, 'FTPZ',
            'Enter a new folder name:')
        if ok:
            self.ftp.mkd(text)
        self.ftp_lst()

    def rename_file(self):
        text, ok = QInputDialog.getText(self, 'FTPZ',
            'Enter a new file name:')
        a = self.FTP_tree.itemAt(self.position).text(0)
        if ok:
            self.ftp.rename(a, text)
            self.ftp_lst()

    def delete_file(self):
        self.name_file = self.FTP_tree.itemAt(self.position)
        self.ftp.delete(self.name_file.text(0))
        self.ftp_lst()

    def dwc(self):
        url = self.ftp.pwd()
        b = -2
        while True:
            if url[b] == '/':
                c = url[:b]
                break
            else:
                b -= 1
        if c == '':
            c = '/'
        return c



    def uploading_files_to_server(self):
        f1 = open(self.filePath, "rb")
        filename = QUrl(self.filePath).fileName() 
        self.ftp.storbinary("STOR" + filename, f1, 1024, progress())
        f1.close()


    def downloading_from_server_for_toolbar(self):
        b = f'{self.ftp.pwd()}/{self.FTP_tree.itemAt(self.position).text(0)}'
        c = QUrl(b).fileName()

        if self.FTP_tree.itemAt(self.position).text(0) == '..':
            self.ftp.cwd(self.dwc())
            self.ftp_lst()

        elif QFileInfo(c).completeSuffix() == '':
            self.ftp.cwd(b)
            self.ftp_lst()

        else:
            way = easygui.diropenbox()
            host_file = os.path.join(
                way, self.FTP_tree.itemAt(self.position).text(0)
            )

            try:
                with open(host_file, 'wb') as local_file:
                    self.ftp.retrbinary('RETR ' + self.FTP_tree.itemAt(self.position).text(0), local_file.write)
            except ftplib.error_perm:
                pass

    def downloading_from_server(self):
        b = f'{self.ftp.pwd()}/{self.FTP_tree.currentItem().text(0)}'
        c = QUrl(b).fileName()

        if self.FTP_tree.currentItem().text(0) == '..':
            self.ftp.cwd(self.dwc())
            self.ftp_lst()

        elif QFileInfo(c).completeSuffix() == '':
            self.ftp.cwd(b)  
            self.ftp_lst()

        else:
            way = easygui.diropenbox()
            host_file = os.path.join(
                way, self.FTP_tree.currentItem().text(0)
            )

            try:
                with open(host_file, 'wb') as local_file:
                    self.ftp.retrbinary('RETR ' + self.FTP_tree.currentItem().text(0), local_file.write)
            except ftplib.error_perm:
                pass


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = App()
    ex.resize(640, 480)                    
    ex.show()                              
    sys.exit(app.exec_())

Функция uploading_files_to_server, закачивает файл на сервер. После нажатия на файл в дереве каталогов Файл начинает отправляться на сервер.

Минимально рабочий пример:

import sys
from PyQt5 import QtCore, QtGui, QtWidgets                                
from PyQt5.QtWidgets import QWidget, QGridLayout, QPushButton, QGraphicsOpacityEffect, QTreeWidgetItem, QVBoxLayout, QMenu, QSplitter
from PyQt5.QtWidgets import QMainWindow, QAction, qApp, QApplication, QMenuBar, QFileSystemModel, QHBoxLayout, QShortcut, QInputDialog
from PyQt5.QtCore import QUrl, QRect, QFileInfo, Qt, QSize, QDir
from PyQt5.QtGui import QIcon, QKeySequence
import os
import ftplib


class App(QWidget):
    def __init__(self):
        super().__init__()
        self.ftp = ftplib.FTP('192.168.0.1' ,'Artem' ,'1204')
        self.splitter = QSplitter(Qt.Horizontal)
        self.hbox = QHBoxLayout(self)
        self.hbox.addWidget(self.splitter)

        self.model = QFileSystemModel(self)
        self.model.setRootPath('')
        self.tree = QtWidgets.QTreeView()
        self.tree.setModel(self.model)
        self.tree.setAnimated(False)
        self.tree.setIndentation(20)
        self.tree.setSortingEnabled(True)

        self.tree.clicked.connect(self.on_treeView_clicked)
        self.tree.clicked.connect(self.uploading_files_to_server)
        self.splitter.addWidget(self.tree)       

        self.columns = ['Name', 'Size']
        self.setLayout(self.hbox)

        self.FTP_tree = QtWidgets.QTreeWidget()
        self.FTP_tree.setHeaderLabels(self.columns)
        self.FTP_tree.itemDoubleClicked.connect(self.downloading_from_server)
        self.splitter.addWidget(self.FTP_tree)

        self.i = 1                     

        self.ftp_lst()

    @QtCore.pyqtSlot(QtCore.QModelIndex)
    def on_treeView_clicked(self, index):
        indexItem = self.model.index(index.row(), 0, index.parent())
        self.filePath = self.model.filePath(indexItem)
        if QFileInfo(self.filePath).completeSuffix() != '':
            return self.filePath
        else: 
            pass

    def uploading_files_to_server(self):
        f1 = open(self.filePath, "rb")
        self.filename = QUrl(self.filePath).fileName() 
        self.filesize = os.path.getsize(self.filePath)
        self.ftp.storbinary('STOR ' + self.filename, f1, 2048)
        self.ftp_lst()
        f1.close()

    def ftp_lst(self):
        self.FTP_tree.clear()
        self.FTP_tree.setHeaderLabels(self.columns)
        self.FTP_tree.setDisabled(False)
        self.FTP_item1 = QTreeWidgetItem(self.FTP_tree, ['..'])
        self.nlst = self.ftp.nlst()
        self.nlst_len = len(self.nlst)
        self.FTP_item1.setFont(0, QtGui.QFont('Segoe UI', 10))
        for i in self.nlst:
            j = []
            j.append(i)    
            j.append(str(self.ftp.size(i)))
            self.FTP_item1 = QTreeWidgetItem(self.FTP_tree, j)
            self.FTP_item1.setFont(0, QtGui.QFont('Segoe UI', 9))
            self.FTP_item1.setFont(1, QtGui.QFont('Segoe UI', 9))
            b = j[0]
            c = QUrl(b).fileName()
            expansion = QFileInfo(c).completeSuffix()

    def downloading_from_server(self):
        b = f'{self.ftp.pwd()}/{self.FTP_tree.currentItem().text(0)}'
        c = QUrl(b).fileName()

        if QFileInfo(c).completeSuffix() == '':
            self.ftp.cwd(b)  
            self.ftp_lst()

        else:
            way = easygui.diropenbox()
            host_file = os.path.join(
                way, self.FTP_tree.currentItem().text(0)
            )

            try:
                with open(host_file, 'wb') as local_file:
                    self.ftp.retrbinary('RETR ' + self.FTP_tree.currentItem().text(0), local_file.write)
            except ftplib.error_perm:
                pass


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = App()
    ex.resize(640, 480)                    
    ex.show()                              
    sys.exit(app.exec_())  

Ответы (1 шт):

Автор решения: eri

progress() - не вижу где определенна.

туда подставь сигнал, который свяжи с прогресс баром.

Выгрузку файлов нужно обернуть в QRunnable или QThread.

Если выделить код, который не работает с интерфейсом в отдельный класс - то не требуется каждую функцию отдельно отправлять в тред. В тред отправляется весь класс. Также разделение интерфейса и логики делает код проще для модернизации.

Вот отрефакторил минимальный пример на сигналах - слотах:

import sys
from PyQt5 import QtCore, QtGui, QtWidgets                                
from PyQt5.QtWidgets import QWidget, QPushButton, QTreeWidgetItem, QVBoxLayout, QProgressBar
from PyQt5.QtWidgets import QApplication, QFileDialog
import os
import ftplib
import time


class myFtp(QtCore.QObject):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.ftp = ftplib.FTP()

    onConnected = QtCore.pyqtSignal()
    onFile = QtCore.pyqtSignal(str,str,str)
    onList = QtCore.pyqtSignal()
    onUploadStart = QtCore.pyqtSignal('qint64')
    onUploadProgress = QtCore.pyqtSignal('qint64')


    @QtCore.pyqtSlot()    
    def connect(self):
        self.ftp.connect(host='127.0.0.1', port=2121)
        self.ftp.login(user='myuser',passwd='change_this_password')
        self.onConnected.emit()


    @QtCore.pyqtSlot()    
    def list(self):
        self.onList.emit()
        self.nlst = self.ftp.mlsd('')
        for item, prps in self.nlst:
            print(item, prps)
            self.onFile.emit( item, prps['type'], prps['size'] )


    @QtCore.pyqtSlot(str)
    def upload(self, filename):
        giga = 0 # чтоб передавать кило,мега,гигабайты в прогресс бар если файл большой
        size = os.path.getsize(filename)
        while size > 2147483647:
            size = size >> 10
            giga += 10

        self.onUploadStart.emit(size)

        name = os.path.basename(filename)
        progress = 0

        def onprogress(data):
            nonlocal progress
            progress+=len(data)
            time.sleep(0.01)
            print(progress, size, progress >> giga)
            self.onUploadProgress.emit(progress >> giga)

        with open(filename, "rb") as f1:
            self.ftp.storbinary('STOR ' + name, f1, 2048, callback=onprogress)

        self.list()


class App(QWidget):
    def __init__(self):
        super().__init__()

        self.ftp = myFtp()

        self.worker_thread = QtCore.QThread()
        self.ftp.moveToThread(self.worker_thread)
        self.worker_thread.start()

        self.box = QVBoxLayout(self)

        self.FTP_tree = QtWidgets.QTreeWidget()
        self.FTP_tree.setHeaderLabels(['Name', 'Type', 'Size'])
        self.box.addWidget(self.FTP_tree)

        self.ftp.onList.connect(self.FTP_tree.clear)
        self.ftp.onFile.connect(self.onFile)


        self.btn = QPushButton()
        self.btn.setText('Upload')

        self.box.addWidget(self.btn)

        self.setLayout(self.box)

        self.filedialog = QFileDialog()
        self.filedialog.setFileMode(QFileDialog.ExistingFile)
        self.filedialog.fileSelected.connect(self.ftp.upload)

        self.btn.clicked.connect(self.filedialog.open)


        self.progress = QProgressBar()

        self.box.addWidget(self.progress)
        self.ftp.onUploadStart.connect( self.progress.setMaximum )
        self.ftp.onUploadProgress.connect( self.progress.setValue )

        self.ftp.connect()
        self.ftp.list()

    @QtCore.pyqtSlot(str,str,str)   
    def onFile(self, name, typ, size):
        QTreeWidgetItem(self.FTP_tree, [name, typ, size])





if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = App()
    ex.resize(640, 480)                    
    ex.show()                              
    sys.exit(app.exec_())  
→ Ссылка