问题描述
我正在尝试使用pyqt5线程工作程序同时下载多个文件。
我正在使用回调(由paramiko支持)功能来确定下载百分比。我想同时更新特定下载的进度条。我无法弄清楚如何将progressBar详细信息传递给回调函数。 我想将“ progressBar”传递给测试函数(这是一个回调函数)
from PyQt5 import QtCore,QtGui,QtWidgets
import threading
import time
from concurrent.futures import ThreadPoolExecutor
from configurationFileRead import readConfigFile
import paramiko
import os
from functools import partial
class FileDownload1(QtCore.QThread):
percentage = QtCore.pyqtSignal(str,str)
def __init__(self,fileList,serverList,listProgressBar):
super().__init__()
self.fileList = fileList
self.serverList = serverList
self.listProgressBar = listProgressBar
def test(self,size,fileSize):
sPercentage=((fileSize - size)/fileSize)*100
if sPercentage != 100:
sPercentage = 100 - sPercentage
print(sPercentage)
def _download(self,fileName,serverName,progressBar):
userId = readConfigFile().getUserId(serverName)
password = readConfigFile().getpassword(serverName)
ipAddress = readConfigFile().getIpAddress(serverName)
logPath = readConfigFile().getLogPath(serverName)
ssh = paramiko.SSHClient()
ssh.load_system_host_keys()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(ipAddress,username=userId,password=password)
ftp_client=ssh.open_sftp()
print(str(os.getcwd()))
try:
ftp_client.get(logPath+"/"+fileName,str(os.getcwd())+"/"+fileName,callback = lambda s,t : self.percetage.emit(s,t))
except Excption as e:
print(e)
ftp_client.close()
ssh.close()
def run(self):
j = 0
with ThreadPoolExecutor(max_workers = 1) as executor:
while(j < len(self.fileList)):
if(self.fileList[j].isChecked()):
future= executor.submit(self._download,self.fileList[j].text(),self.serverList[j].text(),self.listProgressBar[j])
j = j+1
print("Download END")
class logSearch(QtCore.QThread):
new_signal = QtCore.pyqtSignal(dict)
def __init__(self,serachString,archiveFlg,component):
super().__init__()
self.serverList = serverList
self.searchString = serachString
self.archiveFlg = archiveFlg
self.component = component
self.result = {}
def fileSearch(self,server,searchText):
try:
userId = readConfigFile().getUserId(server.text())
password = readConfigFile().getpassword(server.text())
ipAddress = readConfigFile().getIpAddress(server.text())
logPath = ""
if(not self.archiveFlg):
logPath = readConfigFile().getLogPath(server.text())
else:
logPath = readConfigFile().getLogArchivePath(server.text())
ssh = paramiko.SSHClient()
ssh.load_system_host_keys()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(ipAddress,password=password)
if(not self.archiveFlg):
if self.component == "":
ssh_stdin,ssh_stdout,ssh_stderr = ssh.exec_command("cd "+logPath+";for i in *.log\ndo grep -li '"+self.searchString+"' $i\ndone")
else:
ssh_stdin,ssh_stderr = ssh.exec_command("cd "+logPath+";for i in "+self.component+"_*.log\ndo grep -li '"+self.searchString+"' \"$i\"\ndone")
else:
print(logPath)
ssh_stdin,ssh_stderr = ssh.exec_command("cd "+logPath+";grep -lri '"+self.searchString+"' .")
temp1 = ssh_stderr.read()
print(temp1)
temp = ssh_stdout.read().decode('utf-8')
print(temp)
temp =temp.strip()
files = list(temp.split("\n"))
files = list(filter(None,files))
i = len(files)
j=0
tempDict = {}
while(j < i):
ssh_stdin,ssh_stderr = ssh.exec_command("cd "+logPath+";ls -l "+files[j])
temp = ssh_stdout.read().decode('utf-8')
tempLi = list(temp.split(" "))
tempLi = list(filter(None,tempLi))
fileSize = tempLi[4]
tempFileSize = int(fileSize)
if(tempFileSize < 1024):
fileSize = str(round(tempFileSize,2)) + " B"
else:
tempFileSize = tempFileSize/1024
if(tempFileSize < 1024):
fileSize = str(round(tempFileSize,2)) + " KB"
else:
tempFileSize = tempFileSize/1024
if(tempFileSize < 1024):
fileSize = str(round(tempFileSize,2))+ " MB"
else:
tempFileSize = tempFileSize/1024
fileSize = str(round(tempFileSize,2)) + " GB"
fileDate = str(tempLi[5])+" "+str(tempLi[6])+" "+str(tempLi[7])
tempLi.clear()
tempDict[files[j]] = {'Size':fileSize,'Date':fileDate}
j = j+1
self.result[server.text()]= tempDict
ssh.close()
except Exception as e:
print(e)
def run(self):
i=len(self.serverList)
mxW=0
if(i == 1):
mxW = 1
elif(i == 2 or i == 3 or i == 4):
mxW = 2
elif(i == 5 or i == 6):
mxW = 3
else:
mxW = 5
with ThreadPoolExecutor(max_workers = mxW) as executor:
j=0
try:
while(j < i):
future = executor.submit(self.fileSearch,self.serverList[j],self.searchString)
j = j+1
except Exception as e:
print(e)
self.new_signal.emit(self.result)
class Ui_MainWindow(object):
def _Validate (self):
validateFlag = True
if(str(self.searchString.text())== ""):
self.searchString.setStyleSheet("border: 2px solid red;")
self.searchString.setFocus()
validateFlag = False
else:
self.searchString.setStyleSheet("border: 1px solid;")
if(len(self.serverList.selectedItems())) == 0:
self.serverList.setStyleSheet("border: 2px solid red;")
validateFlag = False
elif len(self.serverList.selectedItems()) > 8:
self.selectedServer.setText("You can only Choose Upto 8 Server")
self.selectedServer.setStyleSheet("color:blue;font:Bold")
self.serverList.setStyleSheet("border: 2px solid red;")
validateFlag = False
elif len(self.serverList.selectedItems()) > 1 and self.specificFileFlag.isChecked() == True:
self.selectedServer.setText("Select only one Server")
self.selectedServer.setStyleSheet("color:red;font:Bold")
validateFlag = False
else:
self.serverList.setStyleSheet("border: 1px solid;")
if(validateFlag):
self.downloadSelected.setdisabled(True)
i=len(self.listProgressBar)
n=0
while(i > 0):
self.listProgressBar[n].deleteLater()
self.listCheckBox[n].deleteLater()
self.listDateLabel[n].deleteLater()
self.listSizeLabel[n].deleteLater()
self.listServerLabel[n].deleteLater()
i = i-1;
n=n+1
self.listProgressBar.clear()
self.listCheckBox.clear()
self.listDateLabel.clear()
self.listSizeLabel.clear()
self.listServerLabel.clear()
self.submit.setdisabled(True)
self.errorLabel.setText("Search Started...")
self.logSearch = logSearch(self.serverList.selectedItems(),self.searchString.text(),self.searchArchive.isChecked(),self.comonentComboBox.currentText())
self.logSearch.new_signal.connect(self.printResult)
self.logSearch.start()
def printResult(self,result):
self.errorLabel.setText("Search Completed")
serverList = list(result.keys())
print(result)
l = len(serverList)
k=0
m = 0
i = 0
while(i < l):
logNameList = list(result[serverList[i]].keys())
n= len(logNameList)
j=0
while(j < n):
self.listCheckBox.append(QtWidgets.QCheckBox())
self.listSizeLabel.append(QtWidgets.QLabel(result[serverList[i]][logNameList[j]]['Size']))
self.listDateLabel.append(QtWidgets.QLabel(result[serverList[i]][logNameList[j]]['Date']))
self.listCheckBox[m].setText(logNameList[j])
self.gridLayout_2.addWidget(self.listCheckBox[m],m,0)
self.listServerLabel.append(QtWidgets.QLabel())
self.listServerLabel[m].setText(serverList[i])
self.gridLayout_2.addWidget(self.listServerLabel[m],1)
self.gridLayout_2.addWidget(self.listSizeLabel[m],2)
self.gridLayout_2.addWidget(self.listDateLabel[m],3)
self.listProgressBar.append(QtWidgets.QProgressBar())
self.listProgressBar[m].setValue(0)
self.gridLayout_2.addWidget(self.listProgressBar[m],4)
j = j+1
m=m+1
i = i+1
self.submit.setdisabled(False)
self.downloadSelected.setdisabled(False)
def hello122(self):
print("invoked")
def _FileDownload(self):
self.test = FileDownload1(self.listCheckBox,self.listServerLabel,self.listProgressBar)
self.test.percentage.connect(self.hello122)
self.test.start()
def _ArchiveFlag(self):
if (self.searchArchive.isChecked()):
self.autodownload.setChecked(True)
self.autodownload.setdisabled(True)
else:
self.autodownload.setdisabled(False)
def _FileDownloadFlag(self):
if(self.specificFileFlag.isChecked()):
self.label.setText("<html><head/><body><p><span style=\" font-weight:600; color:#000000;\">File Name</span><span style=\" font-weight:600; color:#ff0000;\">*</span></p></body></html>")
self.submit.setText("Download File")
self.autodownload.setChecked(False)
self.autodownload.setdisabled(True)
self.searchArchive.setdisabled(True)
self.comonentComboBox.hide()
self.downloadSelected.setdisabled(True)
else:
self.label.setText("<html><head/><body><p><span style=\" font-weight:600; color:#000000;\">Search String</span><span style=\" font-weight:600; color:#ff0000;\">*</span></p></body></html>")
self.submit.setText("Search")
self.comonentComboBox.show()
self.autodownload.setdisabled(False)
self.searchArchive.setdisabled(False)
def _serverList(self):
if len(self.serverList.selectedItems()) > 8 :
self.selectedServer.setText("You can only Choose Upto 8 Server")
self.selectedServer.setStyleSheet("color:red;font:Bold")
elif len(self.serverList.selectedItems()) > 1 and self.specificFileFlag.isChecked() == True:
self.selectedServer.setText("Select only one Server")
self.selectedServer.setStyleSheet("color:red;font:Bold")
elif len(self.serverList.selectedItems()) == 0:
self.selectedServer.setText("")
else:
self.selectedServer.setText(str([item.text() for item in self.serverList.selectedItems()]))
self.selectedServer.setStyleSheet("color:black;font:regular")
self.serverList.setStyleSheet("border: 1px solid;")
def setupUi(self,MainWindow):
MainWindow.setobjectName("MainWindow")
MainWindow.resize(823,588)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred,QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth())
MainWindow.setSizePolicy(sizePolicy)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setobjectName("centralwidget")
self.verticalLayoutWidget = QtWidgets.QWidget(self.centralwidget)
self.verticalLayoutWidget.setGeometry(QtCore.QRect(20,40,761,60))
self.verticalLayoutWidget.setobjectName("verticalLayoutWidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget)
self.verticalLayout.setContentsMargins(0,0)
self.verticalLayout.setobjectName("verticalLayout")
self.gridLayout = QtWidgets.qgridLayout()
self.gridLayout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint)
self.gridLayout.setobjectName("gridLayout")
self.label = QtWidgets.QLabel(self.verticalLayoutWidget)
self.label.setobjectName("label")
self.gridLayout.addWidget(self.label,1,QtCore.Qt.AlignLeft)
self.searchString = QtWidgets.QLineEdit(self.verticalLayoutWidget)
self.searchString.setMaximumSize(QtCore.QSize(673,16777215))
self.searchString.setobjectName("searchString")
self.gridLayout.addWidget(self.searchString,1)
self.submit = QtWidgets.QPushButton(self.verticalLayoutWidget)
self.submit.setobjectName("submit")
self.gridLayout.addWidget(self.submit,4,1)
self.componentLabel = QtWidgets.QLabel(self.verticalLayoutWidget)
self.componentLabel.setobjectName("componentLabel")
self.gridLayout.addWidget(self.componentLabel,2,1)
self.comonentComboBox = QtWidgets.QComboBox(self.verticalLayoutWidget)
self.comonentComboBox.setobjectName("comonentComboBox")
self.comonentComboBox.addItem("")
lengthOfComponent = len(readConfigFile().getComponentList())
m=0
while(m < lengthOfComponent):
self.comonentComboBox.addItem(readConfigFile().getComponentList()[m])
m = m+1
self.gridLayout.addWidget(self.comonentComboBox,3,1)
self.verticalLayout.addLayout(self.gridLayout)
self.errorLabel = QtWidgets.QLabel(self.centralwidget)
self.errorLabel.setGeometry(QtCore.QRect(30,10,751,16))
self.errorLabel.setText("")
self.errorLabel.setobjectName("errorLabel")
self.groupBox = QtWidgets.qgroupbox(self.centralwidget)
self.groupBox.setGeometry(QtCore.QRect(40,140,361,151))
self.groupBox.setobjectName("groupBox")
self.serverList = QtWidgets.QListWidget(self.groupBox)
self.serverList.setEnabled(True)
self.serverList.setGeometry(QtCore.QRect(10,20,331,121))
self.serverList.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
self.serverList.setResizeMode(QtWidgets.QListView.Fixed)
self.serverList.setobjectName("serverList")
item = QtWidgets.QListWidgetItem()
lengthOfServers = len(readConfigFile().getServerList())
k=0
while( k < lengthOfServers):
if readConfigFile().getServerList()[k] != "Component":
self.serverList.addItem(readConfigFile().getServerList()[k])
k = k+1
self.groupBox_2 = QtWidgets.qgroupbox(self.centralwidget)
self.groupBox_2.setGeometry(QtCore.QRect(410,151))
self.groupBox_2.setobjectName("groupBox_2")
self.autodownload = QtWidgets.QCheckBox(self.groupBox_2)
self.autodownload.setGeometry(QtCore.QRect(10,30,121,20))
self.autodownload.setobjectName("autodownload")
self.specificFileFlag = QtWidgets.QCheckBox(self.groupBox_2)
self.specificFileFlag.setGeometry(QtCore.QRect(10,60,171,20))
self.specificFileFlag.setobjectName("specificFileFlag")
self.downloadSelected = QtWidgets.QPushButton(self.groupBox_2)
self.downloadSelected.setGeometry(QtCore.QRect(10,97,141,31))
self.downloadSelected.setobjectName("downloadSelected")
self.searchArchive = QtWidgets.QCheckBox(self.groupBox_2)
self.searchArchive.setGeometry(QtCore.QRect(170,20))
self.searchArchive.setobjectName("searchArchive")
self.checkBox = QtWidgets.QCheckBox(self.groupBox_2)
self.checkBox.setGeometry(QtCore.QRect(170,191,21))
self.checkBox.setobjectName("checkBox")
self.label_2 = QtWidgets.QLabel(self.centralwidget)
self.label_2.setGeometry(QtCore.QRect(640,540,161,20))
self.label_2.setobjectName("label_2")
self.selectedServer = QtWidgets.QLabel(self.centralwidget)
self.selectedServer.setGeometry(QtCore.QRect(30,110,21))
self.selectedServer.setText("")
self.selectedServer.setobjectName("selectedServer")
self.serverList.itemSelectionChanged.connect(self._serverList)
self.submit.clicked.connect(self._Validate)
self.horizontalLayoutWidget = QtWidgets.QWidget(self.centralwidget)
self.horizontalLayoutWidget.setGeometry(QtCore.QRect(40,310,731,211))
self.horizontalLayoutWidget.setobjectName("horizontalLayoutWidget")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget)
self.horizontalLayout.setContentsMargins(0,0)
self.horizontalLayout.setobjectName("horizontalLayout")
self.scrollArea = QtWidgets.QScrollArea(self.horizontalLayoutWidget)
self.scrollArea.setWidgetResizable(True)
self.scrollArea.setobjectName("scrollArea")
self.scrollAreaWidgetContents = QtWidgets.QWidget()
self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0,727,207))
self.scrollAreaWidgetContents.setobjectName("scrollAreaWidgetContents")
self.gridLayout_2 = QtWidgets.qgridLayout(self.scrollAreaWidgetContents)
self.gridLayout_2.setContentsMargins(10,10)
self.gridLayout_2.setobjectName("gridLayout_2")
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
self.horizontalLayout.addWidget(self.scrollArea)
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setobjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.listCheckBox = []
self.listProgressBar = []
self.listServerLabel = []
self.listSizeLabel = []
self.listDateLabel = []
self.searchArchive.toggled.connect(self._ArchiveFlag)
self.specificFileFlag.toggled.connect(self._FileDownloadFlag)
self.downloadSelected.clicked.connect(self._FileDownload)
self.downloadSelected.setdisabled(True)
self.checkBox.setdisabled(True)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self,MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setwindowTitle(_translate("MainWindow","MainWindow"))
self.label.setText(_translate("MainWindow","<html><head/><body><p><span style=\" font-weight:600; color:#000000;\">Search String</span><span style=\" font-weight:600; color:#ff0000;\">*</span></p></body></html>"))
self.submit.setText(_translate("MainWindow","Search"))
self.groupBox.setTitle(_translate("MainWindow","Server List"))
__sortingEnabled = self.serverList.isSortingEnabled()
self.serverList.setSortingEnabled(False)
self.serverList.setSortingEnabled(__sortingEnabled)
self.groupBox_2.setTitle(_translate("MainWindow","Other Configuration"))
self.autodownload.setToolTip(_translate("MainWindow","<html><head/><body><p><br/></p></body></html>"))
self.autodownload.setText(_translate("MainWindow","Auto Download"))
self.specificFileFlag.setToolTip(_translate("MainWindow","<html><head/><body><p>write the file name in "Search String" and Click on Search Button</p></body></html>"))
self.specificFileFlag.setText(_translate("MainWindow","Download Specific file"))
self.downloadSelected.setText(_translate("MainWindow","Download Selected"))
self.searchArchive.setText(_translate("MainWindow","Search in Archive"))
self.checkBox.setToolTip(_translate("MainWindow","<html><head/><body><p>This option will try to compress the file in server before downloading</p></body></html>"))
self.checkBox.setText(_translate("MainWindow","Compress Before Download"))
self.label_2.setText(_translate("MainWindow","<html><head/><body><p><span style=\" color:#969696;\">Created by - Sudipto Khan</span></p></body></html>"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
解决方法
您无法访问Qt主线程之外的GUI元素,因此必须将地址列表发送到QThread并使用自定义信号通知进度,然后在主线程中可以将地址用作每个地址的引用酒吧。
我假设您可能正在使用QTableWidget,所以下面的示例使用第一列作为服务器名称,第二列作为文件名称,第三列显示QProgressBar(使用{{3}添加) }。
FileDownload1(QtCore.QThread):
percentage = QtCore.pyqtSignal(str,str,int)
def __init__(self,urlData):
super().__init__()
self.urlData = urlData
def _download(self,fileName,serverName):
# ...
try:
ftp_client.get(
logPath+"/"+fileName,str(os.getcwd())+"/"+fileName,callback = lambda s,t: self.percentage.emit(server,path,int(s / t * 100)))
# ...
def run(self):
j = 0
with ThreadPoolExecutor(max_workers = 1) as executor:
for serverName,fileName in self.urlData:
future = executor.submit(self._download,serverName,fileName)
class MainWindow(QtWidgets.QMainWindow):
# ...
def startDownload(self):
urlData = []
self.progressBars = {}
for row in range(self.fileTable.rowCount()):
serverName = self.fileTable.item(row,0).text()
fileName = self.fileTable.item(row,1).text()
urlData.append((serverName,fileName))
progressBar = self.fileTable.cellWidget(row,2)
self.progressBars[(serverName,fileName)] = progressBar
self.downloader = FileDownload1(urlData)
self.downloader.percentage.connect(self.percentageUpdate)
self.downloader.start()
def percentageUpdate(self,percentage):
self.progressBars[(serverName,fileName)].setValue(percentage)