Skip to content

UpgraderDemo 项目分析

项目信息

  • 项目名称: UpgraderDemo
  • 下载链接: UpgraderDemo.rar
  • 分析时间: 2026-03-31

项目概述

UpgraderDemo是一个演示软件自动更新功能的项目,包含两种版本控制模式:按日期(ByDateTime)和按数字版本号(ByNumber)。该项目展示了如何使用Upgrader组件实现HTTP方式的软件更新功能。

文件结构

UpgraderDemo/
├── ByDateTime/                    # 按日期版本控制模式
│   ├── ByDateTime.py             # 主程序文件
│   ├── ByDateTime.xml            # 项目配置文件
│   ├── Extractor_Icon.ico        # 应用程序图标
│   ├── Main.py                   # 主窗体代码
│   ├── Main.pydfm                # 窗体设计文件
│   ├── Main.sct                  # 脚本文件
│   ├── Main.sfm                  # 窗体结构文件
│   └── update0.inf               # 更新配置文件示例
└── ByNumber/                     # 按数字版本控制模式
    ├── ByNumber.py               # 主程序文件
    ├── ByNumber.xml              # 项目配置文件
    ├── Extractor_Icon.ico        # 应用程序图标
    ├── Main.py                   # 主窗体代码
    ├── Main.pydfm                # 窗体设计文件
    ├── Main.sct                  # 脚本文件
    ├── Main.sfm                  # 窗体结构文件
    └── update1.inf               # 更新配置文件示例

主程序文件: ByDateTime.py / ByNumber.py

from glcl import *
from Main import *

def main():
    Application.Initialize()
    Application.Title = 'ByDateTime'  # 或 'ByNumber'
    Application.MainFormOnTaskbar = True
    Application.Icon.LoadFromFile(os.path.join(os.path.dirname(os.path.abspath(__file__)), "Extractor_Icon.ico"))
    MainForm = frmMain(Application)
    MainForm.Show()
    FreeConsole()
    Application.Run()
    MainForm.Free()

if __name__ == '__main__':
    main()

主窗体文件: Main.py

ByDateTime版本

# Powered By Python Studio, The best Python GUI IDE to download from glsite.com.
'''
功能:用于通过Http更新软件

特性:
1、阻塞模式更新
2、具备比较完备的进度控制
3、与autoupgrader组件相比,相对更简单些,但autoupgrader必须要求具备GUI,而这个组件则不需要。
4、具有自动回滚功能。如停止下载或下载失败都会执行回滚操作。
5、可将文件方便地下载到指定目录而不必须都下载到同一目录中。

组件属性:
UpdateInfoURL:更新信息文件的URL地址
VersionPattern:版本控制模式
    vpByNumber:采用数字作为版本号,采用此模式,VersionAsNumber有效
    vpByDateTime:采用日期作为版本号,采用此模式,VersionAsDateTime有效

组件事务:
OnProgress:进度控制
OnFileBegin:文件下载前
OnFileEnd:文件下载后

更新信息文件格式:
[version]
Pattern=1  //VersionPattern (0表示采用vpByDateTime, 1表示采用vpByNumber)
Version=2  //版本号,如果Pattern为0,则这里采用数字,否则使用日期字符串,如:2007-08-03 12:00:00

//下面是文件列表,格式为:本地路径=下载地址
//.表示当前目录,..表示上级目录,跟DOS下的表示是一样的。
[files]
../test/NBServer.exe=http://192.168.1.2:19130/nbmanager/NBServer.exe
./test/blacklist.sys=http://192.168.1.2:19130/nbmanager/blacklist.sys
test/client.exe=http://192.168.1.2:19130/nbmanager/bak/client.exe
config.ini=http://192.168.1.2:19130/nbmanager/config.ini
zend/1.exe=http://192.168.1.2:19130/nbmanager/test/1.exe
zend/2.exe=http://192.168.1.2:19130/nbmanager/test/2.exe
zend/3.exe=http://192.168.1.2:19130/nbmanager/test/3.exe

配置文件中的本地路径可以使用目录变量,如
%Windows%\setup.exe=http://192.168.1.2:19130/setup.exe
即表示将http://192.168.1.2:19130/setup.exe下载到本地的Windows目录下,并改名为setup.exe

可用的目录变量如下:
%Windows%
%System%
%Temp%
%Desktop%
%Programs%
%Personal%
%Startup%
%Recent%
%SendTo%
%StartMenu%
%DesktopDirectory%
%NetHood%
%Fonts%
%Templates%
%Common_StartMenu%
%Common_Programs%
%Common_Startup%
%Common_DesktopDirectory%
%AppData%
%PrintHood%
%Common_Favorites%
%Internet_Cache%
%Cookies%
%History%

使用相关说明,请参看update.inf和Demo(压缩包中的update.inf只是范本,只有放到Http服务器上才会生效)
注:新程序的版本号一定要大于旧程序的版本才会更新
'''

import os
from glcl import *

class frmMain(Form):

    def __init__(self, owner):
        self.ProgressBar1 = ProgressBar(self)
        self.ProgressBar2 = ProgressBar(self)
        self.Memo1 = Memo(self)
        self.Label1 = Label(self)
        self.btnStart = Button(self)
        self.btnPause = Button(self)
        self.btnResume = Button(self)
        self.btnStop = Button(self)
        self.Upgrader1 = Upgrader(self)
        self.LoadProps(os.path.join(os.path.dirname(os.path.abspath(__file__)), "Main.pydfm"))
        self.Upgrader1.OnFileEnd = self.Upgrader1FileEnd
        self.Upgrader1.OnProgress = self.Upgrader1Progress
        self.Upgrader1.OnFileBegin = self.Upgrader1FileBegin
        self.btnStop.OnClick = self.btnStopClick
        self.btnResume.OnClick = self.btnResumeClick
        self.btnPause.OnClick = self.btnPauseClick
        self.btnStart.OnClick = self.btnStartClick
        ''' 这个实例演示的是使用日期更新的方式,为了保证演示效果长期有效,所以将版本
        的日期设置为了一个比较远的,实际使用根据现实情况来。你当前做的更新版本的日期
        设置控件和服务器端的inf文件中的日期,要比用户使用的版本的日期更新一些,这样
        当用户端判断到了有更新日期的版本时,就可以进行更新了。如果你设置的日期是一个
        比用户端版本还更早的日期,那是不会更新的。
        '''

    def btnStartClick(self, Sender):
        if self.Upgrader1.Check(None):      # 检查更新
            self.Upgrader1.Start(None)      # 开始更新
        else:                               # 当前是最新版
            self.Caption = '已经是最新的版本'

    def btnPauseClick(self, Sender):
        self.Upgrader1.Pause()              # 暂停更新

    def btnResumeClick(self, Sender):
        self.Upgrader1.Resume()             # 继续更新

    def btnStopClick(self, Sender):
        self.Upgrader1.Stop()               # 停止更新

    def Upgrader1FileBegin(self, url, localfile, Size):     # 更新开始事件
        self.Memo1.Lines.Add(url + '===>' + localfile)

    def GetTimeString(self, Time) -> str:                   # 计算时间的函数
        if Time >= 3600:
            return '%d小时%2d分钟%2d秒钟'.format((Time // 3600), ((Time % 3600) // 60), (Time % 60))
        else:
            if Time >= 60:
                return '%2d分钟%2d秒钟'.format((Tme // 60), (Time % 60))
            else:
                return str(Time) + '秒钟'

    def Upgrader1Progress(self, ProgressEx, ulStatusCode, szStatusText):        # 更新进度事件
        if ProgressEx.Single.TotalSize != 0:        # 一开始时未获取到单文件大小,需要排除这种情况
            self.Label1.Caption = str(ProgressEx.Single.FinishedSize)           # 下载完成的大小
            self.ProgressBar1.Position = round((ProgressEx.Single.FinishedSize / ProgressEx.Single.TotalSize) * 100)    # 计算单文件进度
        if ProgressEx.General.TotalSize != 0:       # 一开始时未获取到总文件大小,需要排除这种情
            self.ProgressBar2.Position = round((ProgressEx.General.FinishedSize / ProgressEx.General.TotalSize) * 100)  # 计算总文件进度
        self.Label1.Caption = '文件个数:' + str(ProgressEx.FileCount)                         # 文件个数

    def Upgrader1FileEnd(self, url, localfile, Size):
        self.Memo1.Lines.Add('传输完成:'  + localfile)

ByNumber版本

ByNumber版本的Main.py与ByDateTime版本基本相同,主要区别在于注释说明和版本控制模式。

更新配置文件示例

ByDateTime/update0.inf (按日期版本控制)

[Version]
Pattern=0
Version=2049/10/1 12:00:00

[files]
.\ByDateTime.exe=http://myupdate.top/COMPONENTS/Upgrader/ByDateTime.exe
.\1.mp4=http://myupdate.top/COMPONENTS/Upgrader/1.mp4
.\readme.txt=http://myupdate.top/COMPONENTS/Upgrader/readme.txt

ByNumber/update1.inf (按数字版本控制)

[Version]
Pattern=1
Version=2

[files]
.\ByNumber.exe=http://myupdate.top/COMPONENTS/Upgrader/ByNumber.exe
.\1.mp4=http://myupdate.top/COMPONENTS/Upgrader/1.mp4
.\readme.txt=http://myupdate.top/COMPONENTS/Upgrader/readme.txt

设计文件: Main.sct

def btnStartClick(Sender):
def btnPauseClick(Sender):
def btnResumeClick(Sender):
def btnStopClick(Sender):
def Upgrader1FileBegin(url, localfile, Size):
def Upgrader1Progress(ProgressEx, ulStatusCode, szStatusText):
def Upgrader1FileEnd(url, localfile, Size):

设计文件: Main.sfm (示例结构)

object frmMain: TForm
  Left = 0
  Top = 0
  Caption = 'frmMain'
  ClientHeight = 400
  ClientWidth = 600
  object ProgressBar1: TProgressBar
    Left = 20
    Top = 20
    Width = 560
    Height = 25
  end
  object ProgressBar2: TProgressBar
    Left = 20
    Top = 60
    Width = 560
    Height = 25
  end
  object Memo1: TMemo
    Left = 20
    Top = 100
    Width = 560
    Height = 200
  end
  object Label1: TLabel
    Left = 20
    Top = 320
    Width = 200
    Height = 20
    Caption = '文件个数:0'
  end
  object btnStart: TButton
    Left = 20
    Top = 350
    Width = 75
    Height = 25
    Caption = '开始'
    OnClick = btnStartClick
  end
  object btnPause: TButton
    Left = 110
    Top = 350
    Width = 75
    Height = 25
    Caption = '暂停'
    OnClick = btnPauseClick
  end
  object btnResume: TButton
    Left = 200
    Top = 350
    Width = 75
    Height = 25
    Caption = '继续'
    OnClick = btnResumeClick
  end
  object btnStop: TButton
    Left = 290
    Top = 350
    Width = 75
    Height = 25
    Caption = '停止'
    OnClick = btnStopClick
  end
  object Upgrader1: TUpgrader
    Left = 380
    Top = 350
    OnFileBegin = Upgrader1FileBegin
    OnProgress = Upgrader1Progress
    OnFileEnd = Upgrader1FileEnd
  end
end

其他文件

  • Extractor_Icon.ico: 应用程序图标文件
  • ByDateTime.xml / ByNumber.xml: 项目配置文件
  • Main.pydfm: 窗体设计文件(二进制格式)

详细分析

功能概述

UpgraderDemo展示了两种软件自动更新方案:

  1. 按日期版本控制 (ByDateTime)
  2. 使用日期作为版本标识
  3. 适用于需要按时间顺序更新的场景
  4. 示例版本:2049/10/1 12:00:00

  5. 按数字版本控制 (ByNumber)

  6. 使用数字作为版本标识
  7. 适用于传统的版本号管理
  8. 示例版本:2

核心功能特性

  1. 阻塞模式更新: 更新过程中会阻塞用户界面,确保更新完整性
  2. 进度控制: 提供详细的下载进度显示,包括单个文件和总体进度
  3. 自动回滚: 下载失败或中断时自动回滚到更新前状态
  4. 灵活的文件下载: 支持将文件下载到任意指定目录
  5. 目录变量支持: 支持系统目录变量(如%Windows%、%Temp%等)
  6. 版本检查: 自动检查新版本,只有新版本才会触发更新

使用的组件

  1. 主窗体组件:
  2. frmMain (TForm): 主窗体容器

  3. 界面控件:

  4. ProgressBar1, ProgressBar2 (TProgressBar): 进度条,显示下载进度
  5. Memo1 (TMemo): 文本显示区域,显示下载日志
  6. Label1 (TLabel): 标签,显示文件数量等信息
  7. btnStart, btnPause, btnResume, btnStop (TButton): 控制按钮

  8. 核心功能组件:

  9. Upgrader1 (TUpgrader): 更新器组件,负责HTTP下载和版本管理

技术特点

1. 版本控制模式

  • vpByDateTime: 日期模式,使用日期字符串作为版本号
  • vpByNumber: 数字模式,使用整数作为版本号

2. 事件处理机制

  • OnFileBegin: 文件开始下载时触发
  • OnProgress: 下载进度更新时触发
  • OnFileEnd: 文件下载完成时触发

3. 进度信息结构

  • ProgressEx.Single: 单个文件的进度信息
  • ProgressEx.General: 总体进度信息
  • ProgressEx.FileCount: 文件总数

4. 更新配置文件格式

  • [Version] 部分: 定义版本控制模式和版本号
  • [files] 部分: 定义文件下载映射关系

窗体属性

  • caption: frmMain
  • height: 400
  • width: 600

代码分析

导入的模块: - import os: 操作系统接口模块 - from glcl import *: GUI组件库

定义的类: - frmMain: 主窗体类,继承自Form

定义的方法: - __init__: 构造函数,初始化窗体和控件 - btnStartClick: 开始更新按钮点击事件 - btnPauseClick: 暂停更新按钮点击事件 - btnResumeClick: 继续更新按钮点击事件 - btnStopClick: 停止更新按钮点击事件 - Upgrader1FileBegin: 文件开始下载事件 - Upgrader1Progress: 下载进度更新事件 - Upgrader1FileEnd: 文件下载完成事件 - GetTimeString: 辅助函数,格式化时间显示

事件绑定: - self.btnStart.OnClick = self.btnStartClick - self.btnPause.OnClick = self.btnPauseClick - self.btnResume.OnClick = self.btnResumeClick - self.btnStop.OnClick = self.btnStopClick - self.Upgrader1.OnFileBegin = self.Upgrader1FileBegin - self.Upgrader1.OnProgress = self.Upgrader1Progress - self.Upgrader1.OnFileEnd = self.Upgrader1FileEnd

使用说明

1. 配置更新服务器

  1. update.inf文件上传到HTTP服务器
  2. update.inf中配置正确的版本信息和文件列表
  3. 确保所有需要下载的文件可以通过指定的URL访问

2. 客户端配置

  1. 设置Upgrader1.UpdateInfoURL属性为更新配置文件的URL
  2. 根据需求设置VersionPattern属性(vpByDateTime或vpByNumber)
  3. 设置相应的版本号属性(