cxfreeze打包python程序的方法說明(生成安裝包,實現桌面快捷方式、刪除快捷方式)

1、cxfreeze基礎

 一、cxfreeze功能

python代碼文件轉exe方法有三種,分別是cx_freeze,py2exe,PyInstaller,這三種方式各有千秋,本人只用過py2exe和cxfreeze,這裏重點說明cxfreeze。html

 

二、安裝包下載地址

 https://sourceforge.net/projects/cx-freeze/files/python

 

三、cxfree的官方說明文檔

 http://cx-freeze.readthedocs.io/en/latest/distutils.htmles6

 

2、cxfreeze使用方法

一、cxfreeze命令方法

cxfreeze etax.py --target-dir out/      #把etax.py 打包成etax.exe,放在out目錄下 數據庫

 

二、編寫cxsetup.py編譯腳本,而後用py去執行。

來一個簡單的需求:編譯etax.py生成test.exe文件。小程序

a、步驟1,先編寫一個cxsetup.py腳本文件windows

複製代碼
#coding=utf-8
#cxsetup.py代碼
from cx_Freeze import setup, Executable
setup(
    name="test",
    version="1.0",
    description="Test application",
    author="zhongtang",
    executables=[Executable("etax.py")]
)
複製代碼

能夠看到,cxsetup.py實際上是一個py程序,該程序調用了cx_Freeze 包中的setup、Executable類。app

而後用python執行cxsetup.py,就能夠實現編譯exe。less

另外補充一點,cxsetup.py能夠隨意起名,默認都叫xxsetup.pypython2.7

 

編譯後的文件屬性以下:ide

 

 

 b、步驟2,執行py命令

#build方式打包成exe文件,能夠脫離python環境運行

python cxsetup.py build 

 

#bdist_msi方式能夠打包成windows下msi格式的安裝包文件

python cxsetup.py bdist_msi 

 

3、cxsetup.py程序的進階寫法

仍是以一個實例說明,需求以下:

一、et是一個基於wxpython編寫的圖形界面的小程序

二、et中使用了ini配置文件,文件名爲et.ini

三、et中使用了PIL類,並使用圖片文件et.jpg

四、et程序一共包含4個文件,主程序名爲eTMain.py

五、打包py成exe,脫離python環境運行

六、生成windows下的msi安裝包,該安裝包運行後會安裝桌面快捷方式、開始菜單快捷方式、刪除程序的快捷方式,而且開始菜單有子目錄。

 

 上cxsetup.py代碼

複製代碼
#!/usr/bin/python
#coding=utf-8
# create by :joshua zou 2016.7.23

import sys
import traceback
from cx_Freeze import setup, Executable
import msilib

# Dependencies are automatically detected, but it might need fine tuning.

#中文須要顯式用gbk方式編碼
product_name = u'異體'.encode('gbk')
unproduct_name = u'卸載異體'.encode('gbk')
product_desc = u"異體客戶端程序 Ver1.0".encode("gbk")

#uuid叫通用惟一識別碼,後面再卸載快捷方式中要用到
product_code = msilib.gen_uuid()
#主程序手動命名
target_name= 'etMain.exe'


build_exe_options = {
    "include_files":["et.ini","et.jpg",'data'],    
    #包含外圍的ini、jpg文件,以及data目錄下全部文件,以上全部的文件路徑都是相對於cxsetup.py的路徑。
    "packages": ["os","wx"],                #包含用到的包
    "includes": ["PIL","traceback"], 
    "excludes": ["tkinter"],                #提出wx裏tkinter包
    "path": sys.path,                       #指定上述的尋找路徑
    "icon": "et.ico"                        #指定ico文件
};

#快捷方式表,這裏定義了三個快捷方式
shortcut_table = [
     
     #一、桌面快捷方式
    ("DesktopShortcut",           # Shortcut
     "DesktopFolder",             # Directory_ ,必須在Directory表中
     product_name,                # Name
     "TARGETDIR",                 # Component_,必須在Component表中
     "[TARGETDIR]"+target_name,   # Target
     None,                        # Arguments
     product_desc,                # Description
     None,                        # Hotkey
     None,                        # Icon
     None,                        # IconIndex
     None,                        # ShowCmd
     'TARGETDIR'                  # WkDir
     ),
    
    #二、開始菜單快捷方式
    ("StartupShortcut",           # Shortcut
     "MenuDir",                   # Directory_
     product_name,                # Name
     "TARGETDIR",                 # Component_
     "[TARGETDIR]"+target_name,   # Target
     None,                        # Arguments
     product_desc,                # Description
     None,                        # Hotkey
     None,                        # Icon
     None,                        # IconIndex
     None,                        # ShowCmd
     'TARGETDIR'                  # WkDir
     ),
    
    #3、程序卸載快捷方式
    ("UniShortcut",              # Shortcut
     "MenuDir",                  # Directory_
     unproduct_name,             # Name
     "TARGETDIR",                # Component_
     "[System64Folder]msiexec.exe",  # Target
     r"/x"+product_code,         # Arguments
     product_desc,               # Description      None,                       # Hotkey      None,                       # Icon      None,                       # IconIndex      None,                       # ShowCmd      'TARGETDIR'                 # WkDir      )           ] #手動建設的目錄,在這裏定義。 ''' 自定義目錄說明: ============== 一、3個字段分別爲 Directory,Directory_Parent,DefaultDir 二、字段1指目錄名,能夠隨意命名,並在後面直接使用 三、字段2是指字段1的上級目錄,上級目錄自己也是須要預先定義,除了某些系統自動定義的目錄,譬如桌面快捷方式中使用DesktopFolder 參考網址 https://msdn.microsoft.com/en-us/library/aa372452(v=vs.85).aspx ''' directories = [      ( "ProgramMenuFolder","TARGETDIR","." ),      ( "MenuDir", "ProgramMenuFolder", product_name)      ] # Now create the table dictionary # 也可把directories放到data裏。 ''' 快捷方式說明: ============ 一、windows的msi安裝包文件,自己都帶一個install database,包含不少表(用一個Orca軟件能夠看到)。 二、下面的 Directory、Shortcut都是msi數據庫中的表,因此冒號前面的名字是固定的(貌似大小寫是區分的)。 三、data節點實際上是擴展不少自定義的東西,譬如前面的directories的配置,其實cxfreeze中代碼的內容之一,就是把相關配置數據寫入到msi數據庫的對應表中 參考網址:https://msdn.microsoft.com/en-us/library/aa367441(v=vs.85).aspx ''' msi_data = {#"Directory":directories ,             "Shortcut": shortcut_table            } # Change some default MSI options and specify the use of the above defined tables #注意product_code是我擴展的,現有的官網cx_freeze不支持該參數,爲此簡單修改了cx_freeze包的代碼,後面貼上修改的代碼。 bdist_msi_options = { 'data': msi_data,                       'upgrade_code': '{9f21e33d-48f7-cf34-33e9-efcfd80eed10}',                       'add_to_path': False,                       'directories': directories,                       'product_code': product_code,                       'initial_target_dir': r'[ProgramFilesFolder]\%s' % (product_name)}                        # GUI applications require a different base on Windows (the default is for a # console application). base = None; if sys.platform == "win32":      base = "Win32GUI" #簡易方式定義快捷方式,放到Executeable()裏。 #shortcutName = "AppName", #shortcutDir = "ProgramMenuFolder"  setup(  name = "et",         author='et china corp',         version = "1.0",         description = product_desc.decode('gbk'),         options = {"build_exe": build_exe_options,                    "bdist_msi": bdist_msi_options},         executables = [Executable("etMain.py",                                   targetName= target_name,                                   compress = True,                                    base=base)                        ]) 
複製代碼

 

4、補充說明

一、有關windows install msi 文件

能夠去microsoft的官網學習學習,https://msdn.microsoft.com/en-us/library/aa372860(v=vs.85).aspx

 

二、Orca編輯工具

查看修改msi文件數據庫表的工具,Orca(msi編輯工具) 4.5.6 中文綠色版 。

絕對堪稱神器,貼個圖片,這玩意太棒了(本文不少寫法就是仿照python2.7的安裝文件的數據,結合cxfree代碼琢磨出來的)。

 

 

三、擴展的cxfreeze代碼

前文在cxsetup.exe中我提到自定義了product_code參數,這個參數在官方版本的cxfreeze是不支持的(官方版本的productcode是直接寫死的代碼msilib.gen_uuid())。

因此擴展product_code配置的目的,就是由於在卸載Shortcut,須要用到 msiexec.exe /x {productcode}。

 

修改原理:

將 msilib.gen_uuid()放到cxsetup.py中,並做爲product_code參數傳給cxfreeze。

在cxfreeze中判斷product_code參數是否認義,沒定義則默認取msilib.gen_uuid(),有定義則使用定義值。

修改點:

cx_Free/windist.py文件。

修改點一、

class bdist_msi(distutils.command.bdist_msi.bdist_msi):
    user_options = distutils.command.bdist_msi.bdist_msi.user_options + [
        ('add-to-path=', None, 'add target dir to PATH environment variable'),
        ('upgrade-code=', None, 'upgrade code to use'),
        ('initial-target-dir=', None, 'initial target directory'),
        ('target-name=', None, 'name of the file to create'),
        ('directories=', None, 'list of 3-tuples of directories to create'),
        ('data=', None, 'dictionary of data indexed by table name'),
        # add by joshua zou 2016.07.23
        ('product-code=', None, 'product code to use')
    ]

 修改點二、

    def finalize_options(self):
        distutils.command.bdist_msi.bdist_msi.finalize_options(self)
        name = self.distribution.get_name()
        fullname = self.distribution.get_fullname()
        if self.initial_target_dir is None:
            if distutils.util.get_platform() == "win-amd64":
                programFilesFolder = "ProgramFiles64Folder"
            else:
                programFilesFolder = "ProgramFilesFolder"
            self.initial_target_dir = r"[%s]\%s" % (programFilesFolder, name)
        if self.add_to_path is None:
            self.add_to_path = False
        if self.target_name is None:
            self.target_name = fullname
        if not self.target_name.lower().endswith(".msi"):
            platform = distutils.util.get_platform().replace("win-", "")
            self.target_name = "%s-%s.msi" % (self.target_name, platform)
        if not os.path.isabs(self.target_name):
            self.target_name = os.path.join(self.dist_dir, self.target_name)
        if self.directories is None:
            self.directories = []
        if self.data is None:
            self.data = {}
        # add by joshua zou 2016.7
        if self.product_code is None:
            self.product_code = msilib.gen_uuid()

修改點三、

  def initialize_options(self):
        distutils.command.bdist_msi.bdist_msi.initialize_options(self)
        self.upgrade_code = None
        self.add_to_path = None
        self.initial_target_dir = None
        self.target_name = None
        self.directories = None
        self.data = None
        # add by joshua zou 2016.7
        self.product_code=None

代碼點四、

    def run(self):
        if not self.skip_build:
            self.run_command('build')
        install = self.reinitialize_command('install', reinit_subcommands = 1)
        install.prefix = self.bdist_dir
        install.skip_build = self.skip_build
        install.warn_dir = 0
        distutils.log.info("installing to %s", self.bdist_dir)
        install.ensure_finalized()
        install.run()
        self.mkpath(self.dist_dir)
        fullname = self.distribution.get_fullname()
        if os.path.exists(self.target_name):
            os.unlink(self.target_name)
        metadata = self.distribution.metadata
        author = metadata.author or metadata.maintainer or "UNKNOWN"
        version = metadata.get_version()
        sversion = "%d.%d.%d" % \
                distutils.version.StrictVersion(version).version
        '''
        modified by joshua zou 2016.7
        self.db = msilib.init_database(self.target_name, msilib.schema,
                self.distribution.metadata.name, msilib.gen_uuid(), sversion,
                author)
        '''
        self.db = msilib.init_database(self.target_name, msilib.schema,
                        self.distribution.metadata.name, self.product_code, sversion,
                        author)       
        msilib.add_tables(self.db, msilib.sequence)

 

完整源碼

複製代碼
import distutils.command.bdist_msi
import distutils.errors
import distutils.util
import msilib
import os

__all__ = [ "bdist_msi" ]

# force the remove existing products action to happen first since Windows
# installer appears to be braindead and doesn't handle files shared between
# different "products" very well
sequence = msilib.sequence.InstallExecuteSequence

for index, info in enumerate(sequence):
    if info[0] == 'RemoveExistingProducts':
        sequence[index] = (info[0], info[1], 1450)


class bdist_msi(distutils.command.bdist_msi.bdist_msi):
    user_options = distutils.command.bdist_msi.bdist_msi.user_options + [
        ('add-to-path=', None, 'add target dir to PATH environment variable'),
        ('upgrade-code=', None, 'upgrade code to use'),
        ('initial-target-dir=', None, 'initial target directory'),
        ('target-name=', None, 'name of the file to create'),
        ('directories=', None, 'list of 3-tuples of directories to create'),
        ('data=', None, 'dictionary of data indexed by table name'),
        # add by joshua zou 2016.07.23
        ('product-code=', None, 'product code to use')
    ]
    x = y = 50
    width = 370
    height = 300
    title = "[ProductName] Setup"
    modeless = 1
    modal = 3

    def add_config(self, fullname):
        if self.add_to_path:
            msilib.add_data(self.db, 'Environment',
                    [("E_PATH", "Path", r"[~];[TARGETDIR]", "TARGETDIR")])
        if self.directories:
            msilib.add_data(self.db, "Directory", self.directories)
        msilib.add_data(self.db, 'CustomAction',
                [("A_SET_TARGET_DIR", 256 + 51, "TARGETDIR",
                        self.initial_target_dir)])
        msilib.add_data(self.db, 'InstallExecuteSequence',
                [("A_SET_TARGET_DIR", 'TARGETDIR=""', 401)])
        msilib.add_data(self.db, 'InstallUISequence',
                [("PrepareDlg", None, 140),
                 ("A_SET_TARGET_DIR", 'TARGETDIR=""', 401),
                 ("SelectDirectoryDlg", "not Installed", 1230),
                 ("MaintenanceTypeDlg",
                        "Installed and not Resume and not Preselected", 1250),
                 ("ProgressDlg", None, 1280)
                ])
        for index, executable in enumerate(self.distribution.executables):
            if executable.shortcutName is not None \
                    and executable.shortcutDir is not None:
                baseName = os.path.basename(executable.targetName)
                msilib.add_data(self.db, "Shortcut",
                        [("S_APP_%s" % index, executable.shortcutDir,
                                executable.shortcutName, "TARGETDIR",
                                "[TARGETDIR]%s" % baseName, None, None, None,
                                None, None, None, None)])
        for tableName, data in self.data.items():
            msilib.add_data(self.db, tableName, data)

    def add_cancel_dialog(self):
        dialog = msilib.Dialog(self.db, "CancelDlg", 50, 10, 260, 85, 3,
                self.title, "No", "No", "No")
        dialog.text("Text", 48, 15, 194, 30, 3,
                "Are you sure you want to cancel [ProductName] installation?")
        button = dialog.pushbutton("Yes", 72, 57, 56, 17, 3, "Yes", "No")
        button.event("EndDialog", "Exit")         button = dialog.pushbutton("No", 132, 57, 56, 17, 3, "No", "Yes")         button.event("EndDialog", "Return")     def add_error_dialog(self):         dialog = msilib.Dialog(self.db, "ErrorDlg", 50, 10, 330, 101, 65543,                 self.title, "ErrorText", None, None)         dialog.text("ErrorText", 50, 9, 280, 48, 3, "")         for text, x in [("No", 120), ("Yes", 240), ("Abort", 0),                 ("Cancel", 42), ("Ignore", 81), ("Ok", 159), ("Retry", 198)]:             button = dialog.pushbutton(text[0], x, 72, 81, 21, 3, text, None)             button.event("EndDialog", "Error%s" % text)     def add_exit_dialog(self):         dialog = distutils.command.bdist_msi.PyDialog(self.db, "ExitDialog",                 self.x, self.y, self.width, self.height, self.modal,                 self.title, "Finish", "Finish", "Finish")         dialog.title("Completing the [ProductName] installer")         dialog.back("< Back", "Finish", active = False)         dialog.cancel("Cancel", "Back", active = False)         dialog.text("Description", 15, 235, 320, 20, 0x30003,                 "Click the Finish button to exit the installer.")         button = dialog.next("Finish", "Cancel", name = "Finish")         button.event("EndDialog", "Return")     def add_fatal_error_dialog(self):         dialog = distutils.command.bdist_msi.PyDialog(self.db, "FatalError",                 self.x, self.y, self.width, self.height, self.modal,                 self.title, "Finish", "Finish", "Finish")         dialog.title("[ProductName] installer ended prematurely")         dialog.back("< Back", "Finish", active = False)         dialog.cancel("Cancel", "Back", active = False)         dialog.text("Description1", 15, 70, 320, 80, 0x30003,                 "[ProductName] setup ended prematurely because of an error. "                 "Your system has not been modified. To install this program "                 "at a later time, please run the installation again.")         dialog.text("Description2", 15, 155, 320, 20, 0x30003,                 "Click the Finish button to exit the installer.")         button = dialog.next("Finish", "Cancel", name = "Finish")         button.event("EndDialog", "Exit")     def add_files(self):         db = self.db         cab = msilib.CAB("distfiles")         f = msilib.Feature(db, "default", "Default Feature", "Everything", 1,                 directory="TARGETDIR")         f.set_current()         rootdir = os.path.abspath(self.bdist_dir)         root = msilib.Directory(db, cab, None, rootdir, "TARGETDIR",                 "SourceDir")         db.Commit()         todo = [root]         while todo:             dir = todo.pop()             for file in os.listdir(dir.absolute):                 if os.path.isdir(os.path.join(dir.absolute, file)):                     newDir = msilib.Directory(db, cab, dir, file, file,                             "%s|%s" % (dir.make_short(file), file))                     todo.append(newDir)                 else:                     dir.add_file(file)         cab.commit(db)     def add_files_in_use_dialog(self):         dialog = distutils.command.bdist_msi.PyDialog(self.db, "FilesInUse",                 self.x, self.y, self.width, self.height, 19, self.title,                 "Retry", "Retry", "Retry", bitmap = False)         dialog.text("Title", 15, 6, 200, 15, 0x30003,                 r"{\DlgFontBold8}Files in Use")         dialog.text("Description", 20, 23, 280, 20, 0x30003,                 "Some files that need to be updated are currently in use.")         dialog.text("Text", 20, 55, 330, 50, 3,                 "The following applications are using files that need to be "                 "updated by this setup. Close these applications and then "                 "click Retry to continue the installation or Cancel to exit "                 "it.")         dialog.control("List", "ListBox", 20, 107, 330, 130, 7,                 "FileInUseProcess", None, None, None)         button = dialog.back("Exit", "Ignore", name = "Exit")         button.event("EndDialog", "Exit")         button = dialog.next("Ignore", "Retry", name = "Ignore")         button.event("EndDialog", "Ignore")         button = dialog.cancel("Retry", "Exit", name = "Retry")         button.event("EndDialog", "Retry")     def add_maintenance_type_dialog(self):         dialog = distutils.command.bdist_msi.PyDialog(self.db,                 "MaintenanceTypeDlg", self.x, self.y, self.width, self.height,                 self.modal, self.title, "Next", "Next", "Cancel")         dialog.title("Welcome to the [ProductName] Setup Wizard")         dialog.text("BodyText", 15, 63, 330, 42, 3,                 "Select whether you want to repair or remove [ProductName].")         group = dialog.radiogroup("RepairRadioGroup", 15, 108, 330, 60, 3,                 "MaintenanceForm_Action", "", "Next")         group.add("Repair", 0, 18, 300, 17, "&Repair [ProductName]")         group.add("Remove", 0, 36, 300, 17, "Re&move [ProductName]")         dialog.back("< Back", None, active = False)         button = dialog.next("Finish", "Cancel")         button.event("[REINSTALL]", "ALL",                 'MaintenanceForm_Action="Repair"', 5)         button.event("[Progress1]", "Repairing",                 'MaintenanceForm_Action="Repair"', 6)         button.event("[Progress2]", "repairs",                 'MaintenanceForm_Action="Repair"', 7)         button.event("Reinstall", "ALL",                 'MaintenanceForm_Action="Repair"', 8)         button.event("[REMOVE]", "ALL",                 'MaintenanceForm_Action="Remove"', 11)         button.event("[Progress1]", "Removing",                 'MaintenanceForm_Action="Remove"', 12)         button.event("[Progress2]", "removes",                 'MaintenanceForm_Action="Remove"', 13)         button.event("Remove", "ALL",                 'MaintenanceForm_Action="Remove"', 14)         button.event("EndDialog", "Return",                 'MaintenanceForm_Action<>"Change"', 20)         button = dialog.cancel("Cancel", "RepairRadioGroup")         button.event("SpawnDialog", "CancelDlg")     def add_prepare_dialog(self):         dialog = distutils.command.bdist_msi.PyDialog(self.db, "PrepareDlg",                 self.x, self.y, self.width, self.height, self.modeless,                 self.title, "Cancel", "Cancel", "Cancel")         dialog.text("Description", 15, 70, 320, 40, 0x30003,                 "Please wait while the installer prepares to guide you through"                 "the installation.")         dialog.title("Welcome to the [ProductName] installer")         text = dialog.text("ActionText", 15, 110, 320, 20, 0x30003,                 "Pondering...")         text.mapping("ActionText", "Text")         text = dialog.text("ActionData", 15, 135, 320, 30, 0x30003, None)         text.mapping("ActionData", "Text")         dialog.back("Back", None, active = False)         dialog.next("Next", None, active = False)         button = dialog.cancel("Cancel", None)         button.event("SpawnDialog", "CancelDlg")     def add_progress_dialog(self):         dialog = distutils.command.bdist_msi.PyDialog(self.db, "ProgressDlg",                 self.x, self.y, self.width, self.height, self.modeless,                 self.title, "Cancel", "Cancel", "Cancel", bitmap = False)         dialog.text("Title", 20, 15, 200, 15, 0x30003,                 r"{\DlgFontBold8}[Progress1] [ProductName]")         dialog.text("Text", 35, 65, 300, 30, 3,                 "Please wait while the installer [Progress2] [ProductName].")         dialog.text("StatusLabel", 35, 100 ,35, 20, 3, "Status:")         text = dialog.text("ActionText", 70, 100, self.width - 70, 20, 3,                 "Pondering...")         text.mapping("ActionText", "Text")         control = dialog.control("ProgressBar", "ProgressBar", 35, 120, 300,                 10, 65537, None, "Progress done", None, None)         control.mapping("SetProgress", "Progress")         dialog.back("< Back", "Next", active = False)         dialog.next("Next >", "Cancel", active = False)         button = dialog.cancel("Cancel", "Back")         button.event("SpawnDialog", "CancelDlg")     def add_properties(self):         metadata = self.distribution.metadata         props = [                 ('DistVersion', metadata.get_version()),                 ('DefaultUIFont', 'DlgFont8'),                 ('ErrorDialog', 'ErrorDlg'),                 ('Progress1', 'Install'),                 ('Progress2', 'installs'),                 ('MaintenanceForm_Action', 'Repair'),                 ('ALLUSERS', '1')         ]         email = metadata.author_email or metadata.maintainer_email         if email:             props.append(("ARPCONTACT", email))         if metadata.url:             props.append(("ARPURLINFOABOUT", metadata.url))         if self.upgrade_code is not None:             props.append(("UpgradeCode", self.upgrade_code))             msilib.add_data(self.db, 'Property', props)     def add_select_directory_dialog(self):         dialog = distutils.command.bdist_msi.PyDialog(self.db,                 "SelectDirectoryDlg", self.x, self.y, self.width, self.height,                 self.modal, self.title, "Next", "Next", "Cancel")         dialog.title("Select destination directory")         dialog.back("< Back", None, active = False)         button = dialog.next("Next >", "Cancel")         button.event("SetTargetPath", "TARGETDIR", ordering = 1)         button.event("SpawnWaitDialog", "WaitForCostingDlg", ordering = 2)         button.event("EndDialog", "Return", ordering = 3)         button = dialog.cancel("Cancel", "DirectoryCombo")         button.event("SpawnDialog", "CancelDlg")         dialog.control("DirectoryCombo", "DirectoryCombo", 15, 70, 272, 80,                 393219, "TARGETDIR", None, "DirectoryList", None)         dialog.control("DirectoryList", "DirectoryList", 15, 90, 308, 136, 3,                 "TARGETDIR", None, "PathEdit", None)         dialog.control("PathEdit", "PathEdit", 15, 230, 306, 16, 3,                 "TARGETDIR", None, "Next", None)         button = dialog.pushbutton("Up", 306, 70, 18, 18, 3, "Up", None)         button.event("DirectoryListUp", "0")         button = dialog.pushbutton("NewDir", 324, 70, 30, 18, 3, "New", None)         button.event("DirectoryListNew", "0")     def add_text_styles(self):         msilib.add_data(self.db, 'TextStyle',                 [("DlgFont8", "Tahoma", 9, None, 0),                  ("DlgFontBold8", "Tahoma", 8, None, 1),                  ("VerdanaBold10", "Verdana", 10, None, 1),                  ("VerdanaRed9", "Verdana", 9, 255, 0)                 ])     def add_ui(self):         self.add_text_styles()         self.add_error_dialog()         self.add_fatal_error_dialog()         self.add_cancel_dialog()         self.add_exit_dialog()         self.add_user_exit_dialog()         self.add_files_in_use_dialog()         self.add_wait_for_costing_dialog()         self.add_prepare_dialog()         self.add_select_directory_dialog()         self.add_progress_dialog()         self.add_maintenance_type_dialog()     def add_upgrade_config(self, sversion):         if self.upgrade_code is not None:             msilib.add_data(self.db, 'Upgrade',                     [(self.upgrade_code, None, sversion, None, 513, None,                             "REMOVEOLDVERSION"),                      (self.upgrade_code, sversion, None, None, 257, None,                             "REMOVENEWVERSION")                     ])     def add_user_exit_dialog(self):         dialog = distutils.command.bdist_msi.PyDialog(self.db, "UserExit",                 self.x, self.y, self.width, self.height, self.modal,                 self.title, "Finish", "Finish", "Finish")         dialog.title("[ProductName] installer was interrupted")         dialog.back("< Back", "Finish", active = False)         dialog.cancel("Cancel", "Back", active = False)         dialog.text("Description1", 15, 70, 320, 80, 0x30003,                 "[ProductName] setup was interrupted. Your system has not "                 "been modified. To install this program at a later time, "                 "please run the installation again.")         dialog.text("Description2", 15, 155, 320, 20, 0x30003,                 "Click the Finish button to exit the installer.")         button = dialog.next("Finish", "Cancel", name = "Finish")         button.event("EndDialog", "Exit")     def add_wait_for_costing_dialog(self):         dialog = msilib.Dialog(self.db, "WaitForCostingDlg", 50, 10, 260, 85,                 self.modal, self.title, "Return", "Return", "Return")         dialog.text("Text", 48, 15, 194, 30, 3,                 "Please wait while the installer finishes determining your "                 "disk space requirements.")         button = dialog.pushbutton("Return", 102, 57, 56, 17, 3, "Return",                 None)         button.event("EndDialog", "Exit")     def finalize_options(self):         distutils.command.bdist_msi.bdist_msi.finalize_options(self)         name = self.distribution.get_name()         fullname = self.distribution.get_fullname()         if self.initial_target_dir is None:             if distutils.util.get_platform() == "win-amd64":                 programFilesFolder = "ProgramFiles64Folder"             else:                 programFilesFolder = "ProgramFilesFolder"             self.initial_target_dir = r"[%s]\%s" % (programFilesFolder, name)         if self.add_to_path is None:             self.add_to_path = False         if self.target_name is None:             self.target_name = fullname         if not self.target_name.lower().endswith(".msi"):             platform = distutils.util.get_platform().replace("win-", "")             self.target_name = "%s-%s.msi" % (self.target_name, platform)         if not os.path.isabs(self.target_name):             self.target_name = os.path.join(self.dist_dir, self.target_name)         if self.directories is None:             self.directories = []         if self.data is None:             self.data = {}         # add by joshua zou 2016.7         if self.product_code is None:             self.product_code = msilib.gen_uuid()     def initialize_options(self):         distutils.command.bdist_msi.bdist_msi.initialize_options(self)         self.upgrade_code = None         self.add_to_path = None         self.initial_target_dir = None         self.target_name = None         self.directories = None         self.data = None         # add by joshua zou 2016.7         self.product_code=None              def run(self):         if not self.skip_build:             self.run_command('build')         install = self.reinitialize_command('install', reinit_subcommands = 1)         install.prefix = self.bdist_dir         install.skip_build = self.skip_build         install.warn_dir = 0         distutils.log.info("installing to %s", self.bdist_dir)         install.ensure_finalized()         install.run()         self.mkpath(self.dist_dir)         fullname = self.distribution.get_fullname()         if os.path.exists(self.target_name):             os.unlink(self.target_name)         metadata = self.distribution.metadata         author = metadata.author or metadata.maintainer or "UNKNOWN"         version = metadata.get_version()         sversion = "%d.%d.%d" % \                 distutils.version.StrictVersion(version).version         '''         modified by joshua zou 2016.7         self.db = msilib.init_database(self.target_name, msilib.schema,                 self.distribution.metadata.name, msilib.gen_uuid(), sversion,                 author)         '''         self.db = msilib.init_database(self.target_name, msilib.schema,                         self.distribution.metadata.name, self.product_code, sversion,                         author)                 msilib.add_tables(self.db, msilib.sequence)         self.add_properties()         self.add_config(fullname)         self.add_upgrade_config(sversion)         self.add_ui()         self.add_files()         self.db.Commit()         if not self.keep_temp:             distutils.dir_util.remove_tree(self.bdist_dir,                     dry_run = self.dry_run)
複製代碼

 

 

5、總結

至此,cxfreeze的用法基本全了,更深刻的用法,建議你們去閱讀cxfreeze的源碼。

學習python,我的以爲有幾點很是關鍵:

1、查看官方幫助文檔,2、閱讀源碼,3、藉助google(百度上資料太少,並且相對不許確)

 

以上。

相關文章
相關標籤/搜索