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