Python py2exe窗口显示(tkinter)

5

我正在尝试使用py2exe制作exe文件。程序使用Tkinter显示类似弹出窗口的窗口。问题是,当我按照以下方式运行设置时,一切都正常:

setup(windows = [{'script': "msg.py"}], zipfile = None)

但是当我尝试制作一个单文件exe时,它失败了:

setup(windows = [{'script': "msg.py"}], zipfile = None, options = {'py2exe': {'bundle_files': 1, 'compressed': True}})

实际上,最终的exe文件可以正常运行,但它没有显示任何窗口。我读到在Windows 7上可能会出现bundle_files=1的问题,但我也尝试了bundle_files=2,效果相同。 这是我的msg.py脚本:

from win32gui import FindWindow, SetForegroundWindow
from Image import open as iopen
from ImageTk import PhotoImage
from Tkinter import Tk, Label
from threading import Timer
from subprocess import Popen
import os

def Thread(t, fun, arg=None):
    if arg<>None: x = Timer(t, fun, arg)
    else: x = Timer(t, fun)
    x.daemon = True
    x.start()

def NewMessage():
    global root
    if not os.path.exists('dane/MSG'):
        open('dane/MSG', 'w').write('')
        root = Tk()
        img = PhotoImage(iopen("incl/nowa.png"))
        label = Label(root, image=img)
        label.image = img
        label.bind("<Button-1>", Click)
        label.pack()
        root.geometry('-0-40')
        root.wm_attributes("-topmost", 1)
        root.overrideredirect(1)
        root.mainloop()

def Click(event):
    global root, exit
    root.destroy()
    os.remove('dane/MSG')
    OpenApp()
    exit = True

def OpenApp():
    hwnd = FindWindow(None, 'My program name')
    if hwnd: SetForegroundWindow(hwnd)
    else: Popen('app.exe')

root, exit = None, False
NewMessage()

任何想法?我读到了一些关于Tkinter的问题,但是那些是关于编译的。我的脚本已经被编译过了,它没有抛出任何异常,但是窗口没有显示...
3个回答

9
我最终遇到了同样的问题,我的解决方案包括以下步骤:
在你的options = {...}中添加 "dll_excludes": ["tcl85.dll", "tk85.dll"], 然后手动从PYTHON_PATH\DLLs\(在我的情况下是C:\Python27\DLLs)复制这两个DLL文件到你的exe文件所在位置,并尝试运行它。

5
一个替代dll_excludes和手动复制的方法是将py2exe修补程序打补丁,使其知道这些文件必须直接放置在dist目录中。
在build_exe.py中,有一个名为py2exe的类,其中包含一个名为dlls_in_exedir的列表,用于存储必须放在那里的dll。这个列表是在一个名为plat_prepare的函数中设置的,您可以将tclXX.dll和tkXX.dll文件添加到其中,以确保它们被正确复制。
当然,除非你是唯一一个构建应用程序的人,否则你不一定知道需要捆绑哪个Tcl和Tk版本 - 某些人可能已经自己构建了他们的Python,或者使用旧版的Python和旧版的DLL。因此,您需要检查系统实际正在使用哪些版本。py2exe实际上已经在不同的地方执行了这个操作:通过导入内部的_tkinter模块(通常是一个DLL的实际Tk界面),并访问TK_VERSIONTCL_VERSION,您可以生成并添加正确的文件名。
如果其他人要构建您的应用程序,您可能不想让他们修改他们的py2exe安装,因此,以下是如何从您的setup.py进行patch的方法:
import py2exe
py2exe.build_exe.py2exe.old_prepare = py2exe.build_exe.py2exe.plat_prepare
def new_prep(self):
  self.old_prepare()
  from _tkinter import TK_VERSION, TCL_VERSION
  self.dlls_in_exedir.append('tcl{0}.dll'.format(TCL_VERSION.replace('.','')))
  self.dlls_in_exedir.append('tk{0}.dll'.format(TK_VERSION.replace('.','')))
py2exe.build_exe.py2exe.plat_prepare = new_prep

在Windows 7上,即使使用bundle_files=1也可以正常运行。


2

如果您只有一个版本,那么可以通过data_file复制文件。以下是一个完整的示例:

  • WinXP
  • Python2.7.6
  • tk8.5
  • tcl8.5
  • tix8.4.3
  • py2exe 0.6.9

foo.py:

# -*- coding: iso-8859-1 -*-
import Tkinter
"""
sets TCL_LIBRARY, TIX_LIBRARY and TK_LIBRARY - see installation Lib\lib-tk\FixTk.py
"""
Tkinter._test()

Setup.py :

# -*- coding: iso-8859-1 -*-
from distutils.core import setup
import py2exe
import sys
import os
import os.path
sys.argv.append ('py2exe')
setup (
    options    = 
        {'py2exe': 
            { "bundle_files" : 1    # 3 = don't bundle (default) 
                                     # 2 = bundle everything but the Python interpreter 
                                     # 1 = bundle everything, including the Python interpreter
            , "compressed"   : False  # (boolean) create a compressed zipfile
            , "unbuffered"   : False  # if true, use unbuffered binary stdout and stderr
            , "includes"     : 
                [ "Tkinter", "Tkconstants"

                ]
            , "excludes"      : ["tcl", ]
            , "optimize"     : 0  #-O
            , "packages"     : 
                [ 
                ]
            , "dist_dir"     : "foo"
            , "dll_excludes": ["tcl85.dll", "tk85.dll"]
            ,               
            }
        }
    , windows    = 
        ["foo.py"
        ]
    , zipfile    = None
    # the syntax for data files is a list of tuples with (dest_dir, [sourcefiles])
    # if only [sourcefiles] then they are copied to dist_dir 
    , data_files = [   os.path.join (sys.prefix, "DLLs", f) 
                   for f in os.listdir (os.path.join (sys.prefix, "DLLs")) 
                   if  (   f.lower ().startswith (("tcl", "tk")) 
                       and f.lower ().endswith ((".dll", ))
                       )
                    ] 

    , 
)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接