Прогресбар загрузки файла с 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 шт):
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_())