‌Python中Tkinter程序加密(编译)成pyd文件(第9节)


在Python的程序开发中,为了防止源代码泄露或被恶意篡改,我们经常需要对代码进行加密或保护。在上一节教程中,已经介绍了py文件如何批量加密成二进制的pyd文件,并通过‌使用import语句加载‌pyd文件模块‌,使代码模块得到保密。对于Tkinter程序(Python的GUI应用程序),同样可以加密成二进制的pyd文件,再通过‌使用import语句加载‌pyd文件模块。

Tkinter程序加密步骤

步骤1:准备Tkinter程序文件

首先,我们使用Python的Tkinter库来创建一个扫雷(Mine Sweeper)游戏扫雷游戏是一款经典的益智游戏,玩家通过逻辑推理排除地雷,核心规则是通过数字提示判断周围雷区分布。在游戏中,当我们点击一个未知方块时,如果它是地雷,则游戏结束并显示所有地雷隐藏的位置。如果不是地雷,它会显示周围地雷的数量。我们可以使用鼠标右键标记我们认为是地雷的方块。游戏中有“重新开始”和“退出”两个按钮。通过颜色区分已扫地雷与未知方块。游戏效果图如下所示:

Tkinter库创建扫雷(Mine Sweeper)游戏

扫雷游戏完整代码如下所示:

from tkinter import *
import random
def showapp():
    class Mineclear:
        def __init__(self, rows, cols, mines):
            self.rows = rows
            self.cols = cols
            self.mines = mines
            self.app = Tk()
            self.app.title("经典扫雷游戏")
            self.app.geometry("288x400")
            self.app.resizable(False, False)
            self.app.update_idletasks()
            window_width = self.app.winfo_width()
            window_height = self.app.winfo_height()
            screen_width = self.app.winfo_screenwidth()
            screen_height = self.app.winfo_screenheight()
            x = (screen_width - window_width) // 2
            y = (screen_height - window_height) // 2
            self.app.geometry(f"{window_width}x{window_height}+{x}+{y}")
            self.buttons = [[None for _ in range(cols)] for _ in range(rows)]
            self.design()
            self.layout()
            self.begin()
        def design(self):
            for row in range(self.rows):
                for col in range(self.cols):
                    game_button = Button(self.app, width=2, height=1, command=lambda r=row, c=col: self.onclick(r, c))
                    game_button.bind("<Button-3>", lambda event, r=row, c=col: self.true_onclick(r, c))
                    game_button.grid(row=row, column=col)
                    self.buttons[row][col] = game_button

            reset = Button(self.app, text="重新开始", command=self.replay)
            reset.grid(row=self.rows, column=0, pady=5, columnspan=int(self.cols/2))
            exit_button = Button(self.app, text="退出", command=self.app.quit)
            exit_button.grid(row=self.rows, column=int(self.cols/2), pady=5, columnspan=int(self.cols/2))
        def layout(self):
            self.game_list = []
            while len(self.game_list) < self.mines:
                row = random.randint(0, self.rows - 1)
                col = random.randint(0, self.cols - 1)
                if (row, col) not in self.game_list:
                    self.game_list.append((row, col))
        def begin(self):
            self.end = False
            self.flags = 0
            for row in range(self.rows):
                for col in range(self.cols):
                    self.buttons[row][col]["text"] = ""
                    self.buttons[row][col]["bg"] = "#b4b3b3"
        def onclick(self, row, col):
            if self.end:
                return
            game_button = self.buttons[row][col]
            if (row, col) in self.game_list:
                game_button["text"] = "X"
                game_button["bg"] = "#FF0000"
                self.end = True
                self.display_mines()
            else:
                count = self.near_count(row, col)
                if count > 0:
                    game_button["text"] = str(count)
                    game_button["bg"] = "#FFFFFF"
                else:
                    game_button["text"] = ""
                    game_button["bg"] = "#FFFFFF"
                    self.zero_clearing_non_recursive(row, col)
                if self.game_win():
                    self.end = True
                    for r in range(self.rows):
                        for c in range(self.cols):
                            if (r, c) not in self.game_list:
                                self.buttons[r][c]["bg"] = "#00FF00"
        def true_onclick(self, row, col):
            if self.end:
                return
            game_button = self.buttons[row][col]
            if game_button["text"] == "":
                if self.flags < self.mines:
                    game_button["text"] = "*"
                    game_button["bg"] = "#FFFF00"
                    self.flags += 1
                else:
                    return
            elif game_button["text"] == "*":
                game_button["text"] = ""
                game_button["bg"] = "#b4b3b3"
                self.flags -= 1
        def near_count(self, row, col):
            count = 0
            for r in range(max(0, row - 1), min(row + 2, self.rows)):
                for c in range(max(0, col - 1), min(col + 2, self.cols)):
                    if (r, c) in self.game_list:
                        count += 1
            return count
        def zero_clearing(self, row, col):
            group = [(row, col)]
            while group:
                r, c = group.pop(0)
                game_button = self.buttons[r][c]
                if game_button["text"] == "" and (r, c) not in self.game_list:
                    count = self.near_count(r, c)
                    if count > 0:
                        game_button["text"] = str(count)
                        game_button["bg"] = "#FFFFFF"
                    else:
                        game_button["text"] = ""
                        game_button["bg"] = "#FFFFFF"
                        for r2 in range(max(0, r - 1), min(r + 2, self.rows)):
                            for c2 in range(max(0, c - 1), min(c + 2, self.cols)):
                                if (r2, c2) not in self.game_list and self.buttons[r2][c2]["text"] == "" and (r2, c2) not in group:
                                    group.append((r2, c2))
        def zero_clearing_non_recursive(self, row, col):
            visited = set()
            group = [(row, col)]
            while group:
                r, c = group.pop(0)
                if (r, c) in visited:
                    continue
                visited.add((r, c))
                game_button = self.buttons[r][c]
                if game_button["text"] == "" and (r, c) not in self.game_list:
                    count = self.near_count(r, c)
                    if count > 0:
                        game_button["text"] = str(count)
                        game_button["bg"] = "#FFFFFF"
                    else:
                        game_button["text"] = ""
                        game_button["bg"] = "#FFFFFF"
                        for r2 in range(max(0, r - 1), min(r + 2, self.rows)):
                            for c2 in range(max(0, c - 1), min(c + 2, self.cols)):
                                if (r2, c2) not in self.game_list:
                                    group.append((r2, c2))
        def display_mines(self):
            for mine in self.game_list:
                self.buttons[mine[0]][mine[1]]["text"] = "X"
                self.buttons[mine[0]][mine[1]]["bg"] = "#FF0000"
        def game_win(self):
            return self.flags == self.mines and all(game_button["text"]!= "" or (row, col) in self.game_list for row, row_buttons in enumerate(self.buttons) for col, game_button in enumerate(row_buttons))
        def replay(self):
            self.begin()
            self.layout()

    rows = 12
    cols = 12
    mines = 18
    mine_game = Mineclear(rows, cols, mines)
    mine_game.app.mainloop()

if __name__ == '__main__':
    showapp()

我们把以上游戏代码保存为minesweeper.py文件,再通过上一节教程中介绍的方法,把minesweeper.py文件编译成minesweeper.pyd文件。

步骤2:为Tkinter程序提供运行文件

在Pyhint编辑器的文件夹内,把上面已编译的minesweeper.pyd文件保存到“Pyhint\Learn-Python\test”文件夹内,在“Pyhint\Learn-Python\test”文件夹内再创建一个main.py运行脚本文件,main.py文件代码如下所示:

main.py:

from minesweeper import showapp

mygames = showapp()

最后,通过Pyhint编辑器运行“Pyhint\Learn-Python\test”文件夹内的main.py文件,就可以运行扫雷游戏程序,这个方法可以有效实现Tkinter程序的加密或保护,以防止源代码泄露。