Python py2exe窗口显示(tkinter)

2024-04-26 01:33:37 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试用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运行没有问题,但它不显示任何窗口。我读过Windows7上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有一些问题,但是有编译方面的问题。我的脚本已编译,它不会抛出任何异常,但不会显示窗口。。。


Tags: frompyimportnonetrueostkinterdef
3条回答

除了dll排除和手动复制之外,另一种方法是修补py2exe,以知道这些文件必须直接放在dist目录中。

在build_exe.py中,有一个名为py2exe的类,它包含一个用于dll的列表dlls_in_exedir,该列表必须放在那里。此列表是在名为plat_prepare的函数中设置的,您可以向其中添加tclXX.dll和tkXX.dll文件,以确保它们被正确复制。

当然,除非您是唯一一个构建此版本的人,否则您不一定知道需要捆绑哪个Tcl和Tk版本-可能有人自己构建了自己的Python,或者正在使用带有旧dll的旧Python。因此,您需要检查系统实际使用的版本。py2exe实际上已经在另一个地方实现了这一点:通过导入内部的_tkinter模块(实际的Tk接口,通常是一个DLL)并访问TK_VERSIONTCL_VERSION,然后可以使用它来生成和添加正确的文件名。

如果其他人应该构建你的应用程序,你可能不想让他们修改他们的py2exe安装,所以你可以从setup.py中monkeypatch它:

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

我最后遇到了同样的问题,我的解决方案包括执行以下操作:

添加 "dll_excludes": ["tcl85.dll", "tk85.dll"],

在你的options = {...}

然后手动复制这两个dll

PYTHON_PATH\DLLs\(在我的例子中是C:\Python27\DLLs

到exe的位置并尝试运行它。

如果只有一个版本,则可以使用 通过数据文件。下面是一个完整的例子:

  • WinXP系统
  • Python2.7.6
  • tk8.5节
  • tcl8.5系列
  • tix8.4.3节
  • py2exe 0.6.9倍

食物:

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

设置.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", ))
                       )
                    ] 

    , 
)

相关问题 更多 >