cx_Freeze Tkinter 应用程序的构建非常有问题

cx_Freeze Build of Tkinter Application Extremely Buggy

我最近使用tkinter(python版本3.6.1)创建了一个小游戏,并使用cx_Freeze冻结了它。游戏有四个按钮:撤消按钮、重新启动按钮、"find legal moves" 按钮和 "find best move button"。 "find best move" 按钮使用 shelve 数据库来查找前三圈的最佳着法,并使用递归函数在第四圈及以上的过程中动态遍历着法树。我的代码在不应使用按钮时将其禁用。

我确保在安装脚本中包含必要的 DLL,并且我能够 运行 可执行文件而没有错误。但是,直到第四轮(开始使用递归函数时),其中三个按钮才被禁用,并且该应用程序在许多其他方面都非常错误。但是,当我 运行 解冻版本时,它工作得很好。

老实说,我不知道我需要向你们提供哪些代码片段,因为这个问题让我完全不知所措。我唯一的线索是构建中的 pyc 文件与解冻应用程序的大小不同。我知道这很含糊,但我不知道提供哪些具体细节会有用。如果可能的话,我们将不胜感激。

"Find best move"方法:

def _find_best_move(self):
    """Finds best move possible for current game."""
    if len(self.game.moves) <= 3:
        with shelve.open("paths") as db:
            best_paths = db[str(self.game.moves)]
            best_path = choice(best_paths)
    else:
        self.path_finder(self.game)
        best_path = self.path_finder.best_path
    best_move = best_path[len(self.game.moves)]
    best_move = (__class__._add_offset(best_move[0]), best_move[1])
    return best_move

更新按钮状态:

def update_gui(self):
    """Updates GUI to reflect current game conditions."""
    legal_moves = self.game.find_legal_moves()
    if self.game.moves:
        self.undo_btn["state"] = "!disabled"
        self.restart_btn["state"] = "!disabled"
        self.best_move_btn["state"] = "!disabled"
    else:
        self.undo_btn["state"] = "disabled"
        self.restart_btn["state"] = "disabled"
    if legal_moves:
        self.show_moves_btn["state"] = "!disabled"
    else:
        self.show_moves_btn["state"] = "disabled"
    if legal_moves and self.game.moves:
        self.best_move_btn["state"] = "!disabled"
    else:
        self.best_move_btn["state"] = "disabled"

我的 __init__ 文件:

initpath = os.path.dirname(__file__)
os.chdir(os.path.join(initpath, "data"))

PathFinder class(动态遍历移动树):

class PathFinder:
    """Provides methods to find move paths that meet various criteria.

    Designed to be called after the player makes a move.
    """

    _game = None
    best_path = None
    best_score = None

    def __call__(self, game):
        """Call self as function."""
        if not game:
            self._game = DummyGame()
        elif not isinstance(game, DummyGame):
            self._game = DummyGame(game)
        else:
            self._game = game
        moves = self._game.moves
        self.possible_paths = dict.fromkeys(range(1,9))
        root = Node(moves[-1])
        self._find_paths(root)
        self._find_paths.cache_clear()
        found_scores = [score for score in self.possible_paths.keys() if
                        self.possible_paths[score]]
        self.best_score = min(found_scores)
        self.best_path = self.possible_paths[self.best_score]

    @lru_cache(None)
    def _find_paths(self, node):
        """Finds possible paths and records them in 'possible_paths'."""
        legal_moves = self._game.find_legal_moves()
        if not legal_moves:
            score = self._game.peg_count
            if not self.possible_paths[score]:
                self.possible_paths[score] = self._game.moves.copy()
        else:
            children = []
            for peg in legal_moves:
                for move in legal_moves[peg]:
                    children.append(Node((peg, move)))
            for child in children:
                self._game.move(*child.data)
                self._find_paths(child)
        try:
            self._game.undo()
        except IndexError:
            pass

挂钩 class:

class Peg(RawPen):
    """A specialized 'RawPen' that represents a peg."""

    def __init__(self, start_point, graphics):
        """Initialize self. See help(type(self)) for accurate signature."""
        self.graphics = graphics
        self.possible_moves = []
        super().__init__(self.graphics.canvas, "circle", _CFG["undobuffersize"],
                     True)
        self.pen(pendown=False, speed=0, outline=2, fillcolor="red",
             pencolor="black", stretchfactor=(1.25,1.25))
        self.start_point = start_point
        self.goto(start_point)
        self.ondrag(self._remove)
        self.onrelease(self._place)

    def _remove(self, x, y):
        """Removes peg from hole if it has moves."""
        if self.possible_moves:
            self.goto(x,y)

    def _place(self, x, y):
        """Places peg in peg hole if legal."""
        if self.possible_moves:
            target_holes = [tuple(map(add, self.start_point, move)) for move in
                        self.possible_moves]
            distances = [self.distance(hole) for hole in target_holes]
            hole_distances = dict(zip(distances, target_holes))
            nearest_hole = hole_distances[min(hole_distances)]
            if self.distance(nearest_hole) <= 0.45:
                self.goto(nearest_hole)
                peg = self.graphics._subtract_offset(self.start_point)
                move = tuple(map(sub, self.pos(), self.start_point))
                move = tuple(map(int, move))
                self.graphics.game.move(peg, move)
                self.start_point = self.pos()
            else:
                self.goto(self.start_point)

冻结的应用程序将具有与未冻结的应用程序不同的 __value__ 值。你将不得不相应地处理它!这是一个困扰很多人的常见问题。任何假设在文件系统中找到该模块的东西在冻结时都会停止正常工作。另一个问题是模块的动态导入。

documentation 涵盖了这个主题和其他主题,希望对您有所帮助!