如何在Tkinter画布绘制网格并录入数据,开发独立统计程序?
一步步实现你的Tkinter统计工具需求
我帮你梳理并修改代码,解决画布数据录入、统计计算整合的问题,同时给你后续扩展和打包的方案:
一、核心修改:画布上创建2x2数据录入表格
咱们把原来控制台输入的逻辑改成GUI交互形式,在画布上画出网格+输入框,用户直接在窗口里录入A/B/C/D四个单元格的数据,不用再切换到控制台。
二、整合统计计算与结果展示
把Fisher精确检验的逻辑移到Window类里,这样可以直接获取输入框的数据,计算后在画布上显示结果,不用依赖控制台打印。
三、修改后的完整代码
import tkinter as tk import math class Window(tk.Frame): def __init__(self, master=None): super().__init__(master) self.master = master self.main_window() self.widgets() self.create_data_canvas() # 主窗口基础配置 def main_window(self): self.master.title("Quick-Statistics Calculator") self.master.geometry("1000x800") self.pack(fill=tk.BOTH, expand=True) # 菜单栏创建 def widgets(self): main_menu = tk.Menu(self.master, tearoff=0) self.master.config(menu=main_menu) # 文件菜单 file = tk.Menu(main_menu, tearoff=0) file.add_command(label="Save") file.add_separator() file.add_command(label="Exit", command=self.master.quit) main_menu.add_cascade(label="File", menu=file) # 编辑菜单 edit = tk.Menu(main_menu, tearoff=0) edit.add_command(label="Undo") main_menu.add_cascade(label="Edit", menu=edit) # 均值分析菜单 means = tk.Menu(main_menu, tearoff=0) means.add_command(label="Group t") means.add_command(label="Paired t") means.add_separator() means.add_command(label="ANOVA") means.add_separator() means.add_command(label="Mann-Whitney U") means.add_command(label="Wilcoxon rank sum") main_menu.add_cascade(label="Means", menu=means) # 卡方/表格分析菜单 chi = tk.Menu(main_menu, tearoff=0) chi.add_command(label="Chi-Square 2x2 table") chi.add_command(label="Chi-Square for larger table") chi.add_separator() chi.add_command(label="McNemar's Test") chi.add_command(label="Fisher's Exact", command=self.calculate_fishers) main_menu.add_cascade(label="Tables", menu=chi) # 帮助菜单 help_menu = tk.Menu(main_menu, tearoff=0) help_menu.add_command(label="Means Analysis") help_menu.add_command(label="Chi-Square Analysis") main_menu.add_cascade(label="Help", menu=help_menu) # 创建画布与数据录入网格 def create_data_canvas(self): # 创建画布并铺满窗口 self.canvas = tk.Canvas(self, bg="white") self.canvas.pack(fill=tk.BOTH, expand=True) # 绘制2x2数据网格 grid_size = 150 start_x, start_y = 200, 100 # 绘制横线 for y_offset in [0, grid_size, 2*grid_size]: self.canvas.create_line(start_x, start_y + y_offset, start_x + 2*grid_size, start_y + y_offset) # 绘制竖线 for x_offset in [0, grid_size, 2*grid_size]: self.canvas.create_line(start_x + x_offset, start_y, start_x + x_offset, start_y + 2*grid_size) # 添加单元格标签 labels = [("Cell A", start_x+grid_size//2, start_y+grid_size//2), ("Cell B", start_x+grid_size+grid_size//2, start_y+grid_size//2), ("Cell C", start_x+grid_size//2, start_y+grid_size+grid_size//2), ("Cell D", start_x+grid_size+grid_size//2, start_y+grid_size+grid_size//2)] for text, x, y in labels: self.canvas.create_text(x, y - 30, fill="darkblue", font="Times 14 bold", text=text) # 创建输入框并嵌入画布 self.entries = {} entry_positions = [("A", start_x+20, start_y+20), ("B", start_x+grid_size+20, start_y+20), ("C", start_x+20, start_y+grid_size+20), ("D", start_x+grid_size+20, start_y+grid_size+20)] for cell, x, y in entry_positions: entry = tk.Entry(self.canvas, font="Times 16", width=8) self.canvas.create_window(x, y, window=entry, anchor=tk.NW) self.entries[cell] = entry # 添加提示文字 self.canvas.create_text(500, 50, fill="darkblue", font="Times 20 italic bold", text="Enter 2x2 Table Data Below") # 结果显示区域 self.result_text = self.canvas.create_text(500, 400, fill="darkred", font="Times 18 bold", text="") # Fisher精确检验计算逻辑 def calculate_fishers(self): try: # 获取输入框数据并转换为数值 cell_a = float(self.entries["A"].get()) cell_b = float(self.entries["B"].get()) cell_c = float(self.entries["C"].get()) cell_d = float(self.entries["D"].get()) # 计算Fisher精确检验值(注意阶乘只接受整数,先转int) fenum = math.factorial(int(cell_a+cell_b)) * math.factorial(int(cell_c+cell_d)) * \ math.factorial(int(cell_a+cell_c)) * math.factorial(int(cell_b+cell_d)) feden = math.factorial(int(cell_a)) * math.factorial(int(cell_b)) * \ math.factorial(int(cell_c)) * math.factorial(int(cell_d)) * \ math.factorial(int(cell_a+cell_b+cell_c+cell_d)) fe = fenum / feden # 在画布上更新结果 self.canvas.itemconfig(self.result_text, text=f"Fisher's Exact Result: {fe:.4f}") except ValueError: # 处理非数字输入的错误提示 self.canvas.itemconfig(self.result_text, text="Error: Please enter valid numbers!") except math.DomainError: # 处理负数阶乘的错误提示 self.canvas.itemconfig(self.result_text, text="Error: Values must be non-negative integers!") if __name__ == "__main__": main = tk.Tk() comm_prog = Window(master=main) main.mainloop()
四、后续扩展:绘制正态分布
如果要在画布上绘制正态分布,可以结合Anaconda的numpy生成数据,用matplotlib嵌入Tkinter窗口:
- 安装依赖库:
conda install matplotlib numpy - 在代码中导入
matplotlib.backends.backend_tkagg模块,创建专门的Frame放置绘图区域,生成正态分布数据后调用matplotlib绘制。
五、打包成独立程序
用Anaconda的pyinstaller打包成可执行文件:
- 安装pyinstaller:
conda install pyinstaller - 执行打包命令:
pyinstaller --onefile --windowed your_script_name.py--onefile:生成单个可执行文件--windowed:去掉控制台窗口,适合GUI程序
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

