python代碼文件轉exe方法有三種,分別是cx_freeze,py2exe,PyInstaller,這三種方式各有千秋,本人只用過py2exe和cxfreeze,這里重點說明cxfreeze。
https://sourceforge.net/projects/cx-freeze/files/
http://cx-freeze.readthedocs.io/en/latest/distutils.html
cxfreeze etax.py –target-dir out/ #把etax.py 打包成etax.exe,放在out目錄下
來一個簡單的需求:編譯etax.py生成test.exe文件。
a、步驟1,先編寫一個cxsetup.py腳本文件
#coding=utf-8可以看到,cxsetup.py其實是一個py程序,該程序調用了cx_Freeze 包中的setup、Executable類。
然后用python執行cxsetup.py,就可以實現編譯exe。
另外補充一點,cxsetup.py可以隨意起名,默認都叫xxsetup.py
編譯后的文件屬性如下:
b、步驟2,執行py命令
#build方式打包成exe文件,可以脫離python環境運行
python cxsetup.py build
#bdist_msi方式可以打包成windows下msi格式的安裝包文件
python cxsetup.py bdist_msi
還是以一個實例說明,需求如下:
1、et是一個基于wxpython編寫的圖形界面的小程序
2、et中使用了ini配置文件,文件名為et.ini
3、et中使用了PIL類,并使用圖片文件et.jpg
4、et程序一共包含4個文件,主程序名為eTMain.py
5、打包py成exe,脫離python環境運行
6、生成windows下的msi安裝包,該安裝包運行后會安裝桌面快捷方式、開始菜單快捷方式、刪除程序的快捷方式,并且開始菜單有子目錄。
上cxsetup.py代碼
#!/usr/bin/python importsys
importtraceback
fromcx_Freezeimportsetup,Executable
importmsilib
#Dependenciesareautomaticallydetected,butitmightneedfinetuning.
#中文需要顯式用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=[
#1、桌面快捷方式
(“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
),
#2、開始菜單快捷方式
(“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 ) ] #手動建設的目錄,在這里定義。 ”’ 自定義目錄說明: ============== 1、3個字段分別為Directory,Directory_Parent,DefaultDir 2、字段1指目錄名,可以隨意命名,并在后面直接使用 3、字段2是指字段1的上級目錄,上級目錄本身也是需要預先定義,除了某些系統自動定義的目錄,譬如桌面快捷方式中使用DesktopFolder 參考網址https://msdn.microsoft.com/en-us/library/aa372452(v=vs.85).aspx ”’ directories=[ (“ProgramMenuFolder”,”TARGETDIR”,”.”), (“MenuDir”,“ProgramMenuFolder”,product_name) ] #Nowcreatethetabledictionary #也可把directories放到data里。 ”’ 快捷方式說明: ============ 1、windows的msi安裝包文件,本身都帶一個installdatabase,包含很多表(用一個Orca軟件可以看到)。 2、下面的Directory、Shortcut都是msi數據庫中的表,所以冒號前面的名字是固定的(貌似大小寫是區分的)。 3、data節點其實是擴展很多自定義的東西,譬如前面的directories的配置,其實cxfreeze中代碼的內容之一,就是把相關配置數據寫入到msi數據庫的對應表中 參考網址:https://msdn.microsoft.com/en-us/library/aa367441(v=vs.85).aspx ”’ msi_data={#”Directory”:directories, “Shortcut”:shortcut_table } #ChangesomedefaultMSIoptionsandspecifytheuseoftheabovedefinedtables #注意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)} #GUIapplicationsrequireadifferentbaseonWindows(thedefaultisfora #consoleapplication). base=None; ifsys.platform==“win32”: base=“Win32GUI” #簡易方式定義快捷方式,放到Executeable()里。 #shortcutName=“AppName”, #shortcutDir=“ProgramMenuFolder” setup(name=“et”, author=’etchinacorp’, 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) ])
可以去microsoft的官網學習學習,https://msdn.microsoft.com/en-us/library/aa372860(v=vs.85).aspx
查看修改msi文件數據庫表的工具,Orca(msi編輯工具) 4.5.6 中文綠色版。
絕對堪稱神器,貼個圖片,這玩意太棒了(本文很多寫法就是仿照python2.7的安裝文件的數據,結合cxfree代碼琢磨出來的)。
前文在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)
__all__=[“bdist_msi”]
#forcetheremoveexistingproductsactiontohappenfirstsinceWindows
#installerappearstobebraindeadanddoesn’thandlefilessharedbetween
#different“products”verywell
sequence=msilib.sequence.InstallExecuteSequence
forindex,infoinenumerate(sequence):
ifinfo[0]==‘RemoveExistingProducts‘:
sequence[index]=(info[0],info[1],1450)
classbdist_msi(distutils.command.bdist_msi.bdist_msi):
user_options=distutils.command.bdist_msi.bdist_msi.user_options+[
(‘add-to-path=‘,None,‘addtargetdirtoPATHenvironmentvariable‘),
(‘upgrade-code=‘,None,‘upgradecodetouse‘),
(‘initial-target-dir=‘,None,‘initialtargetdirectory‘),
(‘target-name=‘,None,‘nameofthefiletocreate‘),
(‘directories=‘,None,‘listof3-tuplesofdirectoriestocreate‘),
(‘data=‘,None,‘dictionaryofdataindexedbytablename‘),
#addbyjoshuazou2016.07.23
(‘product-code=‘,None,‘productcodetouse‘)
]
x=y=50
width=370
height=300
title=“[ProductName]Setup“
modeless=1
modal=3
defadd_config(self,fullname):
ifself.add_to_path:
msilib.add_data(self.db,‘Environment‘,
[(“E_PATH“,“Path“,r“[~];[TARGETDIR]“,“TARGETDIR“)])
ifself.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“,“notInstalled“,1230),
(“MaintenanceTypeDlg“,
“InstalledandnotResumeandnotPreselected“,1250),
(“ProgressDlg“,None,1280)
])
forindex,executableinenumerate(self.distribution.executables):
ifexecutable.shortcutNameisnotNone\
andexecutable.shortcutDirisnotNone:
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)])
fortableName,datainself.data.items():
msilib.add_data(self.db,tableName,data)
defadd_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,
“Areyousureyouwanttocancel[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”) defadd_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,“”) fortext,xin[(“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) defadd_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(“Completingthe[ProductName]installer”) dialog.back(“<Back”,“Finish”,active=False) dialog.cancel(“Cancel”,“Back”,active=False) dialog.text(“Description”,15,235,320,20,0x30003, “ClicktheFinishbuttontoexittheinstaller.”) button=dialog.next(“Finish”,“Cancel”,name=“Finish”) button.event(“EndDialog”,“Return”) defadd_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]installerendedprematurely”) dialog.back(“<Back”,“Finish”,active=False) dialog.cancel(“Cancel”,“Back”,active=False) dialog.text(“Description1”,15,70,320,80,0x30003, “[ProductName]setupendedprematurelybecauseofanerror.” “Yoursystemhasnotbeenmodified.Toinstallthisprogram” “atalatertime,pleaseruntheinstallationagain.”) dialog.text(“Description2”,15,155,320,20,0x30003, “ClicktheFinishbuttontoexittheinstaller.”) button=dialog.next(“Finish”,“Cancel”,name=“Finish”) button.event(“EndDialog”,“Exit”) defadd_files(self): db=self.db cab=msilib.CAB(“distfiles”) f=msilib.Feature(db,“default”,“DefaultFeature”,“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] whiletodo: dir=todo.pop() forfileinos.listdir(dir.absolute): ifos.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) defadd_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}FilesinUse”) dialog.text(“Description”,20,23,280,20,0x30003, “Somefilesthatneedtobeupdatedarecurrentlyinuse.”) dialog.text(“Text”,20,55,330,50,3, “Thefollowingapplicationsareusingfilesthatneedtobe” “updatedbythissetup.Closetheseapplicationsandthen” “clickRetrytocontinuetheinstallationorCanceltoexit” “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”) defadd_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(“Welcometothe[ProductName]SetupWizard”) dialog.text(“BodyText”,15,63,330,42,3, “Selectwhetheryouwanttorepairorremove[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”) defadd_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, “Pleasewaitwhiletheinstallerpreparestoguideyouthrough” “theinstallation.”) dialog.title(“Welcometothe[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”) defadd_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, “Pleasewaitwhiletheinstaller[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,“Progressdone”,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”) defadd_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_emailormetadata.maintainer_email ifemail: props.append((“ARPCONTACT”,email)) ifmetadata.url: props.append((“ARPURLINFOABOUT”,metadata.url)) ifself.upgrade_codeisnotNone: props.append((“UpgradeCode”,self.upgrade_code)) msilib.add_data(self.db,‘Property’,props) defadd_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(“Selectdestinationdirectory”) 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”) defadd_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) ]) defadd_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() defadd_upgrade_config(self,sversion): ifself.upgrade_codeisnotNone: msilib.add_data(self.db,‘Upgrade’, [(self.upgrade_code,None,sversion,None,513,None, “REMOVEOLDVERSION”), (self.upgrade_code,sversion,None,None,257,None, “REMOVENEWVERSION”) ]) defadd_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]installerwasinterrupted”) dialog.back(“<Back”,“Finish”,active=False) dialog.cancel(“Cancel”,“Back”,active=False) dialog.text(“Description1”,15,70,320,80,0x30003, “[ProductName]setupwasinterrupted.Yoursystemhasnot” “beenmodified.Toinstallthisprogramatalatertime,” “pleaseruntheinstallationagain.”) dialog.text(“Description2”,15,155,320,20,0x30003, “ClicktheFinishbuttontoexittheinstaller.”) button=dialog.next(“Finish”,“Cancel”,name=“Finish”) button.event(“EndDialog”,“Exit”) defadd_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, “Pleasewaitwhiletheinstallerfinishesdeterminingyour” “diskspacerequirements.”) button=dialog.pushbutton(“Return”,102,57,56,17,3,“Return”, None) button.event(“EndDialog”,“Exit”) deffinalize_options(self): distutils.command.bdist_msi.bdist_msi.finalize_options(self) name=self.distribution.get_name() fullname=self.distribution.get_fullname() ifself.initial_target_dirisNone: ifdistutils.util.get_platform()==“win-amd64”: programFilesFolder=“ProgramFiles64Folder” else: programFilesFolder=“ProgramFilesFolder” self.initial_target_dir=r”[%s]\%s”%(programFilesFolder,name) ifself.add_to_pathisNone: self.add_to_path=False ifself.target_nameisNone: self.target_name=fullname ifnotself.target_name.lower().endswith(“.msi”): platform=distutils.util.get_platform().replace(“win-“,“”) self.target_name=“%s-%s.msi”%(self.target_name,platform) ifnotos.path.isabs(self.target_name): self.target_name=os.path.join(self.dist_dir,self.target_name) ifself.directoriesisNone: self.directories=[] ifself.dataisNone: self.data={} #addbyjoshuazou2016.7 ifself.product_codeisNone: self.product_code=msilib.gen_uuid() definitialize_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 #addbyjoshuazou2016.7 self.product_code=None defrun(self): ifnotself.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(“installingto%s”,self.bdist_dir) install.ensure_finalized() install.run() self.mkpath(self.dist_dir) fullname=self.distribution.get_fullname() ifos.path.exists(self.target_name): os.unlink(self.target_name) metadata=self.distribution.metadata author=metadata.authorormetadata.maintaineror“UNKNOWN” version=metadata.get_version() sversion=“%d.%d.%d”%\ distutils.version.StrictVersion(version).version ”’ modifiedbyjoshuazou2016.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() ifnotself.keep_temp: distutils.dir_util.remove_tree(self.bdist_dir, dry_run=self.dry_run)
至此,cxfreeze的用法基本全了,更深入的用法,建議大家去閱讀cxfreeze的源碼。
學習python,個人覺得有幾點非常關鍵:
一、查看官方幫助文檔,二、閱讀源碼,三、借助google(百度上資料太少,而且相對不準確)
以上。
本文由 貴州做網站公司 整理發布,部分圖文來源于互聯網,如有侵權,請聯系我們刪除,謝謝!
網絡推廣與網站優化公司(網絡優化與推廣專家)作為數字營銷領域的核心服務提供方,其價值在于通過技術手段與策略規劃幫助企業提升線上曝光度、用戶轉化率及品牌影響力。這...
在當今數字化時代,公司網站已成為企業展示形象、傳遞信息和開展業務的重要平臺。然而,對于許多公司來說,網站建設的價格是一個關鍵考量因素。本文將圍繞“公司網站建設價...
在當今的數字化時代,企業網站已成為企業展示形象、吸引客戶和開展業務的重要平臺。然而,對于許多中小企業來說,高昂的網站建設費用可能會成為其發展的瓶頸。幸運的是,隨...
au音頻降噪處理怎么讓聲音不失真?所有音頻降噪過程通過升級軟件使聲音不失真。質量較低的揚聲器通常比質量較高的揚聲器更容易出現低音失真。如果音箱質量低,只能通過硬件升級來提升播放效果。聲音失真可能是由于發送到揚聲器的音量過大。超出揚聲器的處理范圍,此時應該盡量降低發送到揚聲器的音量。au如何去除雜音?au去噪教程具體操作步驟如下:1.打開界面后,導入需要降噪的音頻文件。2.找到音頻中的噪聲,單擊鼠標...
699美元換成人民幣多少?當前美元對人民幣的匯率是1美元=7.0942人民幣1人民幣=0.141美元699美元=4958.8458人民幣參考2019年4月21日的匯率,699美元=4685.5368人民幣;溫馨提示:匯率波動699美元合計人民幣多少?]首先,699是iPhone8的價格,對應中國銀行5888的價格。X是999美元,相當于8388元。關稅10%,增值稅17%。699*6.54*1.1...
西直門三棟大樓叫什么?西直門的三座建筑統稱西環廣場。西環廣場由三面橢圓形玻璃幕墻和一座方形建筑組成,創造了在地鐵上建高樓的歷史。是北京北站旁邊的標志性建筑。行駛到北二環或者西二環的時候非常醒目。其實更像是風水學中三座山的意思,北面有山。北京北站凱德mall是哪個店?它就是凱德mall西直門店,位于西直門立交橋西北角兩點半的拋物大廈,也就是西環廣場,離北京北站很近。北京哪有太平鳥專柜?太平鳥(西直門...