使用 cx_freeze 构建应用程序并执行 .exe 文件后,使用 tkinter 的 GUI 应用程序中的 TreeView 无法正常工作

My TreeView from my GUI app with tkinter doesn't work after I build the app using cx_freeze and executing the .exe file

我用 tkinter 创建了一个应用程序来练习,它类似于一个虚拟钱包来跟踪你的支出。您可以添加不同类别的存款和取款,然后使用 tkinter ttk TreeView 小部件将所有这些都显示在树视图中。这是一张图片,因此更容易理解:

App treeview example

当我 运行 它和我的 main.py 文件一样时,它像任何其他 python 文件一样工作完美,但是当我使用 cx_freeze 将它构建到可执行文件中时,即使构建工作正常并且应用程序 运行s,通过“历史”菜单访问的 TreeView 小部件的站点也不会加载并且显示完全为空,但它不会崩溃或引发任何错误:

App treeview error

这是我的 setup.py 文件代码:

import sys
import os
from cx_Freeze import setup, Executable


application_title = "Monedero App"
main_python_file = "main.py"

PYTHON_INSTALL_DIR = os.path.dirname(sys.executable)
os.environ['TCL_LIBRARY'] = os.path.join(PYTHON_INSTALL_DIR, 'tcl', 'tcl8.6')
os.environ['TK_LIBRARY'] = os.path.join(PYTHON_INSTALL_DIR, 'tcl', 'tk8.6')

base = None
if sys.platform == "win64":
    base = "Win64GUI"
elif sys.platform == "win32":
    base = "Win32GUI"

options = {
    "build_exe": {
        "packages": ["tkinter", "tkinter.ttk", "shelve", "datetime"],
        "include_files": [
            "D:\Programacion\Projects and exercices\Monedero\imagenes\logo.ico",
            (os.path.join(PYTHON_INSTALL_DIR, 'DLLs', 'tk86t.dll'), os.path.join('lib', 'tk86t.dll')),
            (os.path.join(PYTHON_INSTALL_DIR, 'DLLs', 'tcl86t.dll'), os.path.join('lib', 'tcl86t.dll')),
        ],
    }
}

setup(
    name = application_title,
    version = "0.1",
    description = "Test 1",
    options = options,
    executables = [Executable(main_python_file, base=base)],
)

另一个重要的部分是我使用 shelve python 库来保存我的数据。我这样做是因为首先我使用 sqlite 来做,但我遇到了同样的问题,我认为 sqlite 可能是问题所在。现在我不知道可能是什么问题。

我还会附上 TreeView 小部件配置函数代码,以防我从那里更改一些内容:

def configure(self):
    self.parent.refresh()

    try:
        self.historial_frame.destroy()
    except:
        pass

    self.title.config(
        fg = "white",
        bg = "black",
        font = ("Arial", 30),
        padx = 110,
        pady = 20
    )
    self.title.pack(side = tk.TOP, fill = tk.X, expand = tk.YES)

    self.historial_frame = tk.Frame(self)

    style = ttk.Style()
    style.configure("mystyle.Treeview", highlightthickness = 0, bd = 0, font = ('Calibri', 11)) # Modify the font of the body
    style.configure("mystyle.Treeview.Heading", font = ('Calibri', 13,'bold')) # Modify the font of the headings
    style.layout("mystyle.Treeview", [('mystyle.Treeview.treearea', {'sticky': 'nswe'})]) # Remove the borders

    self.historial = ttk.Treeview(self.historial_frame, columns = ('Fecha', 'Cantidad', 'Descripción'), style = "mystyle.Treeview", height = 10)
    self.historial.column("#0", width = 150, stretch = tk.NO)
    self.historial.column("#1", width = 150, stretch = tk.NO)
    self.historial.column("#2", width = 100, stretch = tk.NO)
    self.historial.column("#3", width = 200, minwidth = 100, stretch = tk.YES)
    self.historial.heading("#0", text = "Categoría", anchor = tk.W)
    self.historial.heading("#1", text = "Fecha", anchor = tk.W)
    self.historial.heading("#2", text = "Cantidad", anchor = tk.W)
    self.historial.heading("#3", text = "Descripción", anchor = tk.W)
    self.historial.grid(row=0, column=0, columnspan=15, padx=10, pady=10, sticky="nsew")

    scrollbar = ttk.Scrollbar(self.historial_frame, orient = tk.VERTICAL, command = self.historial.yview)
    scrollbar.grid(row=0, column=15, sticky="nse", pady="10")
    self.historial.configure(yscrollcommand = scrollbar.set)

    self.parent.import_categories()
    total = self.fill_historial()

    totalLabel = tk.Label(self.historial_frame, text = "Balance total: ")
    totalLabel.config(font = ('Calibri', 13))
    totalLabel.grid(row = 1, column = 0, sticky = "w", pady = 10, padx = 5)

    total_dato = tk.StringVar()
    total_dato.set("{:.2f}".format(total) + " €")
    totalLabel_dato = tk.Label(self.historial_frame, textvariable = total_dato, justify = 'left')
    totalLabel_dato.config(font = ('Calibri', 13))
    totalLabel_dato.grid(row = 1, column = 1, sticky = "w", pady = 10, padx = 5)

    self.historial.tag_configure('odd', font = 'Calibri 13') 

    deleteLabel = tk.Label(self.historial_frame, text = "Eliminar registro: ")
    deleteLabel.grid(row = 1, column = 3, sticky = "w", pady = 10, padx = 5)
    deleteButton = tk.Button(self.historial_frame, text="Borrar", command=self.delete_register)
    deleteButton.grid(row = 1, column = 4, sticky = "w", pady = 10, padx = 5)
    

    self.historial_frame.pack()
    self.pack(fill = "both")

因此,如果有人知道发生了什么,我们将不胜感激。如果需要更多信息,请询问。代码或图片上的西班牙名字和文字是因为我来自西班牙:)。

谢谢!

这是一个替代方法,使用 pyinstaller

在你的终端说:

pip install pyinstaller

然后在终端中使用这个命令,比如

pyinstaller -F -w -i"path.ico" name.py

这里,

  • -w 表示程序应该是窗口化的,因为它使用 GUI
  • -F表示程序应该做成一个文件而不是一个目录
  • -i"path.ico" 这可用于为您的 exe 设置图标

并确保使用 dist 文件夹中的 exe,如果您使用任何图像文件,则将 exe 复制到项目目录。

Take a look at the documentation

希望它消除了您的疑问,如果有任何错误请告诉我

干杯