Python py2exe окно, показывающее (tkinter)

Я пытаюсь сделать EXE по py2exe. Программа показывает всплывающее окно, используя Tkinter. Проблема в том, что все работает нормально, когда я запускаю установку следующим образом:

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

но он терпит неудачу, когда я пытаюсь сделать exe с одним файлом:

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

На самом деле финальный исполняемый файл работает без проблем, но он не отображает никаких окон. Я читал, что могут быть проблемы с bundle_files=1 в Windows 7, но я также пробовал 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 ответа

Решение

Я столкнулся с этой же проблемой, мое решение заключалось в следующем:

добавлять"dll_excludes": ["tcl85.dll", "tk85.dll"],

в вашем options = {...}

а затем вручную скопировать эти две библиотеки DLL из

PYTHON_PATH\DLLs\ (в моем случае C:\Python27\DLLs)

к месту вашего exe и попробуйте запустить его.

Альтернативой dll_exclude и ручному копированию является исправление py2exe, чтобы знать, что эти файлы должны быть помещены непосредственно в каталог dist.

Внутри build_exe.py есть класс с именем py2exe, который содержит список dlls_in_exedir для длл, которые должны идти туда. Этот список устанавливается во время функции с именем plat_prepareи вы можете добавить в него файлы tclXX.dll и tkXX.dll, чтобы убедиться, что они копируются правильно.

Конечно, если вы не единственный, кто когда-либо построит это, вы не обязательно будете знать, какие версии Tcl и Tk вам нужно объединить - кто-то, возможно, создал свой Python самостоятельно или использует более старый Python со старыми DLL. Поэтому вам нужно проверить, какие версии на самом деле использует система. py2exe на самом деле уже делает это в другом месте: путем импорта внутреннего _tkinter модуль (фактический интерфейс Tk, обычно DLL) и доступ TK_VERSION а также TCL_VERSION, который затем можно использовать для генерации и добавления правильных имен файлов.

Если другие должны собирать ваше приложение, вы, вероятно, не захотите заставлять их изменять установку py2exe, так что вот как вы можете установить его из своего файла setup.py:

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

Это даже работает с bundle_files=1 на Windows 7.

Если у вас есть только одна версия, вы можете скопировать файлы с помощью 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", ))
                       )
                    ] 

    , 
)
Другие вопросы по тегам