1.軟件打包安裝程序
利用setupfactory軟件進(jìn)行客戶端軟件打包,形成一個(gè)setup安裝程序。
2. 建立FTP服務(wù)器
利用quickeasyftpserver在遠(yuǎn)程服務(wù)器中建立FTP服務(wù)器,放置2個(gè)文件,一個(gè)setup安裝文件,一個(gè)是ver.txt文件,里面寫上軟件的版本號(hào)12位,例如20200917V001。
3. 客戶端程序開(kāi)發(fā)
在客戶端程序中點(diǎn)擊升級(jí)按鈕后
(1) 程序首先刪除本地的上一次的版本和升級(jí)文件,然后從ftp服務(wù)器上下載ver.txt,然后判斷服務(wù)器的setup版本和當(dāng)前軟版本是否一致,不一致,就提示用戶升級(jí)。
(2) 如果用戶同意升級(jí),就在ftp上下載setup安裝文件。
(3) 下載完成后,再開(kāi)一個(gè)線程執(zhí)行setup程序,然后把當(dāng)前的程序關(guān)閉,安裝程序會(huì)覆蓋當(dāng)前的程序。

運(yùn)行界面1

運(yùn)行界面2

提示框
問(wèn)題:
這種方法比較簡(jiǎn)單,主要問(wèn)題是不知道ftp文件的下載進(jìn)度,會(huì)有一直卡死的現(xiàn)象。這個(gè)原因是進(jìn)度條的定時(shí)器程序刷新UI和FTP下載程序在一個(gè)線程中,造成擁塞了。下載時(shí)就不能定時(shí)中斷,刷新UI了
解決方案:
(1) 對(duì)于ftp下載采用異步方式,下載完后發(fā)送信號(hào)給主線程。
(2) 主線程點(diǎn)擊升級(jí)按鈕,綁定子線程和對(duì)應(yīng)的回調(diào)函數(shù)。然后啟動(dòng)ftp子線程。
(3) 在回調(diào)函數(shù)中,執(zhí)行此程序就是下載結(jié)束了,這時(shí)可以在主線程中啟動(dòng),進(jìn)度條滿格,然后執(zhí)行分線程執(zhí)行安裝程序,并在主程序中把自己結(jié)束
代碼如下:
from update import Ui_MainWindow
from PyQt5 import QtWidgetsfrom PyQt5.QtWidgets import QMessageBoximport sysimport osfrom ftplib import FTP # 引入ftp模塊import win32processfrom PyQt5.QtCore import QBasicTimer, QThread, pyqtSignalimport timemycurrent_ver = '20200916V001' # 當(dāng)前軟件版本號(hào)
mynew_ver = ''#異步線程class MyCal(QThread): #自定義一個(gè)信號(hào)名 cal_signal = pyqtSignal(int) #定義信號(hào)返回的數(shù)值類型 #構(gòu)造函數(shù) def __init__(self, mypath, filename,parent=None): #
super(MyCal, self).__init__(parent)
self.mypath = mypath
self.filename=filename
print("分線程:",self.mypath,self.filename)
#析構(gòu)函數(shù) def __del__(self):
self.wait()
#該線程主程序 def run(self):
##ftp下載程序版本程序 ftp = MyFtp('127.0.0.1)
ftp.login('admin', '123456')
ftp.downloadFile(self.mypath, '/down/', self.filename)
ftp.close() print("分線程下載結(jié)束:", self.mypath+self.filename)
self.cal_signal.emit(1) #發(fā)射信號(hào),傳參數(shù)
class MyFtp: ftp = FTP() def __init__(self, host, port=21):
self.ftp.connect(host, port)
def login(self, username, pwd):
self.ftp.set_debuglevel(2) # 打開(kāi)調(diào)試級(jí)別2,顯示詳細(xì)信息
self.ftp.login(username, pwd)
print(self.ftp.welcome)
def downloadFile(self, localpath, remotepath, filename):
os.chdir(localpath) # 切換工作路徑到下載目錄 self.ftp.cwd(remotepath) # 要登錄的ftp目錄
self.ftp.nlst() # 獲取目錄下的文件
file_handle = open(filename, "wb").write # 以寫模式在本地打開(kāi)文件
self.ftp.retrbinary('RETR %s' % os.path.basename(filename), file_handle, blocksize=1024) # 下載ftp文件
# ftp.delete(filename) # 刪除ftp服務(wù)器上的文件 def close(self):
self.ftp.set_debuglevel(0) # 關(guān)閉調(diào)試
self.ftp.quit()
# 主窗體class MainForm(QtWidgets.QMainWindow, Ui_MainWindow): def __init__(self):
super(MainForm, self).__init__()
self.setupUi(self)
self.timer = QBasicTimer()
self.step = 0
# self.myupdate_bt()
# 進(jìn)度條控制定時(shí)器 def timerEvent(self, event):
if self.step >= 100:
self.timer.stop()
self.pushButton_2.setText('開(kāi)始進(jìn)度條')
self.step = 0
self.progressBar.setValue(self.step)
return
self.step = self.step + 1
if self.step>=99:
self.step=99
self.progressBar.setValue(self.step)
# 進(jìn)度條控制 def myprocessbar_bt(self):
pass if self.timer.isActive():
self.timer.stop()
self.pushButton_2.setText('開(kāi)始進(jìn)度條')
else:
self.timer.start(100, self)
self.pushButton_2.setText('停止進(jìn)度條')
def myupdate_bt(self):
pass myhomedir = os.getcwd() mypath = os.getcwd() + '\down\' myfilepath1 = mypath + "ver.txt"
myfilepath2 = mypath + "setup.exe"
# 刪除文件 x1 = os.path.exists(myfilepath1) # True/False if x1 == True:
print("刪除文件:" + myfilepath1)
os.remove(myfilepath1) x1 = os.path.exists(myfilepath2) # True/False if x1 == True:
print("刪除文件:" + myfilepath2)
os.remove(myfilepath2) ##ftp下載程序版本程序 ftp = MyFtp('127.0.0.1)
ftp.login('admin', '123456')
ftp.downloadFile(mypath, '/down/', 'ver.txt')
ftp.close() print("下載結(jié)束:", myfilepath1)
# 判斷版本 with open(myfilepath1, 'rt') as f1:
mynew_ver = f1.readline()[0:12]
self.label_4.setText(mynew_ver)
self.label_2.setText(mycurrent_ver)
if mynew_ver != mycurrent_ver:
x1 = QMessageBox.information(self, "確認(rèn)信息", "有新版本,確認(rèn)是否升級(jí)", QMessageBox.Yes | QMessageBox.No)
if x1 == QMessageBox.No:
os.chdir(myhomedir) return
print("開(kāi)始升級(jí)")
QMessageBox.information(self, "確認(rèn)信息", "開(kāi)始下載程序!!")
self.myprocessbar_bt()#顯示進(jìn)度條
# self.timer.start(100, self)
##擁塞ftp下載程序 # ftp = MyFtp('127.0.0.1')
# ftp.login('admin', '123456')
# ftp.downloadFile(mypath, '/down/', 'setup.exe')
# ftp.close() # print("下載結(jié)束:", myfilepath2)
# QMessageBox.information(self, "確認(rèn)信息", "下載程序結(jié)束!!")
####異步FTP下載 self.cal = MyCal(mypath, 'setup.exe') # 點(diǎn)擊按鈕后新建計(jì)算的線程
self.cal.cal_signal.connect(self.cal_callback) # 連接計(jì)算線程的信號(hào)
self.cal.start() # 開(kāi)始運(yùn)行線程
else:
QMessageBox.information(self, "確認(rèn)信息", "已經(jīng)是最新版本,不用升級(jí)")
os.chdir(myhomedir) return
# 省略 使用接收到線程返回的參數(shù) ###執(zhí)行第三方程序,新線程 #win32process.CreateProcess(myfilepath2, '', None, None, 0, win32process.CREATE_NO_WINDOW, None, None,win32process.STARTUPINFO())
os.chdir(myhomedir) print("主程序退出")
#sys.exit() def cal_callback(self): # 接收到計(jì)算線程信號(hào)后的回掉函數(shù)
pass print('異步ftp下載結(jié)束') self.step=100
self.progressBar.setValue(self.step)
#self.myprocessbar_bt()#顯示進(jìn)度條
myhomedir = os.getcwd() mypath = myhomedir myfilepath1 = mypath + "\ver.txt"
myfilepath2 = mypath + "\setup.exe"
QMessageBox.information(self, "確認(rèn)信息", "下載結(jié)束,開(kāi)始升級(jí)")
print(myfilepath2) win32process.CreateProcess(myfilepath2, '', None, None, 0, win32process.CREATE_NO_WINDOW, None, None,win32process.STARTUPINFO())
sys.exit()# 主程序入口if __name__ == "__main__":
App = QtWidgets.QApplication(sys.argv) win_main = MainForm() win_main.show() sys.exit(app.exec_())
界面如下
