2011-10-25 35 views
11

我在Windows XP上使用Python 2.6和PyGTK 2.22.6從all-in-one installer嘗試爲我的應用程序構建單個文件可執行文件(通過py2exe)。使用py2exe綁定GTK資源

我的問題是,當我運行我的應用程序的腳本(即沒有內置一個.exe文件,就如同.py文件鬆散集合),它使用本地外觀的Windows主題,但是當我運行內置exe我看到默認的GTK主題。

我知道這個問題可以通過將一堆文件複製到由py2exe創建的dist目錄中解決,但是我讀過的所有內容都涉及手動複製數據,而我希望這是構建的自動部分處理。此外,主題上的所有內容(包括the FAQ)都已過時 - PyGTK現在將其文件保存在C:\Python2x\Lib\site-packages\gtk-2.0\runtime\...中,只是複製libetc目錄不能解決問題。

我的問題是:

  1. 我希望能夠以編程發現setup.py而不是硬編碼路徑的GTK運行數據。我該怎麼做呢?

  2. 我需要包含哪些最少的資源?

更新:我可以通過試錯幾乎回答#2。 (即微軟Windows)對於「窩囊廢」的主題工作,我從所需要的文件:

runtime\lib\gtk-2.0\2.10.0\engines\libwimp.dll 
runtime\etc\gtk-2.0\gtkrc 
runtime\share\icons\* 
runtime\share\themes\MS-Windows 

...沒有runtime前綴,但在其他方面具有相同的目錄結構,直接在dist目錄坐由py2exe生成。但2.10.0來自哪裏,因爲gtk.gtk_version(2,22,0)

回答

9

在這裏回答我自己的問題,但如果有人知道更好地隨時回答。其中一些看起來相當脆弱(例如路徑中的版本號),所以如果您知道更好的方法,請進行評論或編輯。

1.查找文件

首先,我用這個代碼實際上找到GTK運行的根源。這是非常具體的你如何安裝運行時,雖然,也許可以用一些測試,共同提高的位置:

#gtk file inclusion 
import gtk 
# The runtime dir is in the same directory as the module: 
GTK_RUNTIME_DIR = os.path.join(
    os.path.split(os.path.dirname(gtk.__file__))[0], "runtime") 

assert os.path.exists(GTK_RUNTIME_DIR), "Cannot find GTK runtime data" 

2.什麼文件,包括

這取決於(一)問題的大小是多少,以及(b)應用程序部署的環境。我的意思是,你是否將它部署到了整個世界,任何人都可以擁有任意的語言環境設置,還是僅僅爲了企業內部使用而不需要翻譯股票字符串?

如果你想讓Windows主題化,你需要包括:

GTK_THEME_DEFAULT = os.path.join("share", "themes", "Default") 
GTK_THEME_WINDOWS = os.path.join("share", "themes", "MS-Windows") 
GTK_GTKRC_DIR = os.path.join("etc", "gtk-2.0") 
GTK_GTKRC = "gtkrc" 
GTK_WIMP_DIR = os.path.join("lib", "gtk-2.0", "2.10.0", "engines") 
GTK_WIMP_DLL = "libwimp.dll" 

如果你想探戈圖標:

GTK_ICONS = os.path.join("share", "icons") 

還有本地化的數據(我省略,但你可能不希望):

GTK_LOCALE_DATA = os.path.join("share", "locale") 

3.湊合一起

首先,這是一個函數,它在給定的點處遍歷文件系統樹,併產生適合於data_files選項的輸出。

def generate_data_files(prefix, tree, file_filter=None): 
    """ 
    Walk the filesystem starting at "prefix" + "tree", producing a list of files 
    suitable for the data_files option to setup(). The prefix will be omitted 
    from the path given to setup(). For example, if you have 

     C:\Python26\Lib\site-packages\gtk-2.0\runtime\etc\... 

    ...and you want your "dist\" dir to contain "etc\..." as a subdirectory, 
    invoke the function as 

     generate_data_files(
      r"C:\Python26\Lib\site-packages\gtk-2.0\runtime", 
      r"etc") 

    If, instead, you want it to contain "runtime\etc\..." use: 

     generate_data_files(
      r"C:\Python26\Lib\site-packages\gtk-2.0", 
      r"runtime\etc") 

    Empty directories are omitted. 

    file_filter(root, fl) is an optional function called with a containing 
    directory and filename of each file. If it returns False, the file is 
    omitted from the results. 
    """ 
    data_files = [] 
    for root, dirs, files in os.walk(os.path.join(prefix, tree)):   
     to_dir = os.path.relpath(root, prefix) 

     if file_filter is not None: 
      file_iter = (fl for fl in files if file_filter(root, fl)) 
     else: 
      file_iter = files 

     data_files.append((to_dir, [os.path.join(root, fl) for fl in file_iter])) 

    non_empties = [(to, fro) for (to, fro) in data_files if fro] 

    return non_empties 

所以,現在你可以調用setup()像這樣:

setup(
    # Other setup args here... 

    data_files = (
        # Use the function above... 
        generate_data_files(GTK_RUNTIME_DIR, GTK_THEME_DEFAULT) + 
        generate_data_files(GTK_RUNTIME_DIR, GTK_THEME_WINDOWS) + 
        generate_data_files(GTK_RUNTIME_DIR, GTK_ICONS) + 

        # ...or include single files manually 
        [ 
         (GTK_GTKRC_DIR, [ 
          os.path.join(GTK_RUNTIME_DIR, 
           GTK_GTKRC_DIR, 
           GTK_GTKRC) 
         ]), 

         (GTK_WIMP_DIR, [ 
          os.path.join(
           GTK_RUNTIME_DIR, 
           GTK_WIMP_DIR, 
           GTK_WIMP_DLL) 
         ]) 
        ] 
       ) 
)