Tkinter路径未按预期变色求助(含Dijkstra算法代码)
问题:无法显示Dijkstra算法计算的最短路径
我的代码会识别Tkinter按钮的位置,通过Dijkstra算法计算起点(黄色按钮)到终点(黑色按钮)的最短路径,之后将路径上的按钮标记为蓝色。但不管选择哪种按钮组合,都无法向用户展示最短路径。
原代码
import sys sys.tracebacklimit = 0 import tkinter as tk import random as rd import heapq def dijkstra(graph, start, finish): # Initialize distances and predecessors distances = {node: float('infinity') for node in graph} distances[start] = 0 predecessors = {node: None for node in graph} # Priority queue to store (distance, node) pairs priority_queue = [(0, start)] while priority_queue: current_distance, current_node = heapq.heappop(priority_queue) # Check if the current path is shorter than the stored distance if current_distance > distances[current_node]: continue for neighbor, weight in graph[current_node].items(): distance = current_distance + weight # If a shorter path is found, update the distance and predecessor if distance < distances[neighbor]: distances[neighbor] = distance predecessors[neighbor] = current_node heapq.heappush(priority_queue, (distance, neighbor)) for finish, distance in distances.items(): sh= (f"la route la plus courte {start} vers {finish}: {distance}") for node, predecessor in predecessors.items(): path = [] current_node = node while current_node is not None: path.insert(0, current_node) current_node = predecessors[current_node] sh_pth=(f"la route la plus courte {start_node} vers {finish}: {' -> '.join(path)}") return distances, predecessors, sh,sh_pth,path d1=1.675 #moyenne de largeur d'un vehicule D1=14 #moyenne de largeur d'une roue d2=4.875 #moyenne de longueur d'un vehicule D2=100 #longueur unitaire des routes choisi arbitrairement a=1 #distance moyenne entre deux vehicules par leurs cotes b=5 # distance moyenne entre deux vehicules successives #avec un petit calcul manuel on a trouve que le nb max moyen de vehicules est 52 def p(n): return(n*((d1+a)*(d2+b))/(D1*D2)) def end(btn): if btn.cget('background') != "yellow" and btn.cget('background') != "black": btn.configure(bg="blue") def set_end(path): for k in range(len(path)): n = n+path[k] i, j = map(int, n.split('|')) end(buttons[i][j]) def status(btn): if btn.cget('background')==None: z=1 elif btn.cget('background')=='yellow': return "yellow" elif btn.cget('background')=='green': return "green" elif btn.cget('background')=='black': return "black" elif btn.cget('background')=='orange': return "orange" elif btn.cget('background')=='red': return "red" window = tk.Tk() window.geometry("500x500") window.title("Exemple") icon = tk.PhotoImage(file='logo.png') window.iconphoto(True,icon) window.config(background='#26282b') epsilon=-1 def click(button): global epsilon, start_node, finish_node epsilon = epsilon + 1 colors = ["yellow", "green", "orange", "red", "black"] color = colors[epsilon % 5] button.config(bg=color) if color == "yellow": start_node = f"{button.grid_info()['row']}|{button.grid_info()['column']}" elif color == "black": finish_node = f"{button.grid_info()['row']}|{button.grid_info()['column']}" buttons = [[None]*15 for _ in range(15)] coefs = [[None]*15 for _ in range(15)] for i in range(15): for j in range(15): buttons[i][j] = tk.Button(window, width=4, height=2, command=lambda i=i, j=j: click(buttons[i][j])) buttons[i][j].grid(row=i, column=j) graph_node={ '2|2': {}, '14|14':{} } start_i=0 start_j=0 finish_i=0 finish_j=0 for i in range(15): for j in range(15): if status(buttons[i][j]) == "yellow": graph_node[str(i)+'|'+str(j)]={} start_node=str(i)+'|'+str(j) start_i=i start_j=j elif status(buttons[i][j]) == "green": coefs[i][j] = p(rd.randrange(1, 17)) graph_node[str(i)+'|'+str(j)] = {} if i < 14: graph_node[str(i)+'|'+str(j)][str(i+1)+'|'+str(j)] = coefs[i+1][j] if i > 0: graph_node[str(i)+'|'+str(j)][str(i-1)+'|'+str(j)] = coefs[i-1][j] if j < 14: graph_node[str(i)+'|'+str(j)][str(i)+'|'+str(j+1)] = coefs[i][j+1] if j > 0: graph_node[str(i)+'|'+str(j)][str(i)+'|'+str(j-1)] = coefs[i][j-1] elif status(buttons[i][j]) == "orange": coefs[i][j]=p(rd.randrange(18,34)) graph_node[str(i)+'|'+str(j)]={} if i < 14: graph_node[str(i)+'|'+str(j)][str(i+1)+'|'+str(j)] = coefs[i+1][j] if i > 0: graph_node[str(i)+'|'+str(j)][str(i-1)+'|'+str(j)] = coefs[i-1][j] if j < 14: graph_node[str(i)+'|'+str(j)][str(i)+'|'+str(j+1)] = coefs[i][j+1] if j > 0: graph_node[str(i)+'|'+str(j)][str(i)+'|'+str(j-1)] = coefs[i][j-1] elif status(buttons[i][j]) == "red": coefs[i][j]=p(rd.randrange(35,52)) graph_node[str(i)+'|'+str(j)]={} if i < 14: graph_node[str(i)+'|'+str(j)][str(i+1)+'|'+str(j)] = coefs[i+1][j] if i > 0: graph_node[str(i)+'|'+str(j)][str(i-1)+'|'+str(j)] = coefs[i-1][j] if j < 14: graph_node[str(i)+'|'+str(j)][str(i)+'|'+str(j+1)] = coefs[i][j+1] if j > 0: graph_node[str(i)+'|'+str(j)][str(i)+'|'+str(j-1)] = coefs[i][j-1] elif status(buttons[i][j])== "black": graph_node[str(i)+'|'+str(j)]={} finish_node=str(i)+'|'+str(j) finish_i=i finish_j=j else: coefs[i][j]=10**100 """for i in range(start_i, finish_i - 1): for j in range(start_j, finish_j - 1): graph_node[str(i)+'|'+str(j)][str(i+1)+'|'+str(j)]=coefs[i+1][j] graph_node[str(i)+'|'+str(j)][str(i-1)+'|'+str(j)]=coefs[i-1][j] graph_node[str(i)+'|'+str(j)][str(i)+'|'+str(j+1)]=coefs[i][j+1] graph_node[str(i)+'|'+str(j)][str(i)+'|'+str(j-1)]=coefs[i][j-1]""" def calculate_and_highlight_path(): distance, predecessors, sh_len, sh_pth, path = dijkstra(graph_node, start_node, finish_node) print(f"Path: {path}") n = start_node for k in range(len(path)): try: if path[k]: n = n + "|" + path[k] i, j = map(int, n.split('|')) print(f"i: {i}, j: {j}") if buttons[i][j].cget('background') not in ["black", "yellow"]: buttons[i][j].config(bg="blue") except KeyError as e: print(f"KeyError: {e}, path: {path}, k: {k}, n: {n}") e_btn = tk.Button(window, width=6, height=2, text='calculer', command=calculate_and_highlight_path) e_btn.grid(row=0, column=18) window.mainloop()
核心问题及修复方案
1. 图构建时机错误
代码在窗口初始化时就构建了graph_node,但此时用户还未点击按钮设置节点颜色,导致图中没有包含用户选择的有效节点,Dijkstra算法无法找到路径。
修复:将图构建逻辑移到calculate_and_highlight_path函数内部,每次计算前重新生成图,确保包含用户最新选择的节点。
2. Dijkstra函数路径生成错误
原函数遍历所有节点生成路径,最终返回的是最后一个节点的路径,而非目标终点的路径,还错误引用了全局变量start_node。
修复:修改Dijkstra函数,仅生成指定终点的路径:
def dijkstra(graph, start, finish): distances = {node: float('infinity') for node in graph} distances[start] = 0 predecessors = {node: None for node in graph} priority_queue = [(0, start)] while priority_queue: current_distance, current_node = heapq.heappop(priority_queue) if current_distance > distances[current_node]: continue for neighbor, weight in graph[current_node].items(): distance = current_distance + weight if distance < distances[neighbor]: distances[neighbor] = distance predecessors[neighbor] = current_node heapq.heappush(priority_queue, (distance, neighbor)) # 仅生成终点的路径 path = [] current_node = finish while current_node is not None: path.insert(0, current_node) current_node = predecessors[current_node] sh = f"从{start}到{finish}的最短路径长度: {distances[finish]}" sh_pth = f"从{start}到{finish}的最短路径: {' -> '.join(path)}" return distances, predecessors, sh, sh_pth, path
3. 路径高亮逻辑错误
原代码拼接节点字符串的方式错误,导致无法正确解析按钮坐标。直接遍历返回的path列表即可,每个元素都是"行|列"格式的字符串。
修复:
def calculate_and_highlight_path(): # 重新构建图 graph_node = {} coefs = [[None]*15 for _ in range(15)] start_node = None finish_node = None for i in range(15): for j in range(15): btn_status = status(buttons[i][j]) node_key = f"{i}|{j}" if btn_status == "yellow": graph_node[node_key] = {} start_node = node_key elif btn_status in ["green", "orange", "red"]: if btn_status == "green": coefs[i][j] = p(rd.randrange(1, 17)) elif btn_status == "orange": coefs[i][j] = p(rd.randrange(18,34)) elif btn_status == "red": coefs[i][j] = p(rd.randrange(35,52)) graph_node[node_key] = {} # 添加有效邻居 if i < 14 and status(buttons[i+1][j]) != "white": graph_node[node_key][f"{i+1}|{j}"] = coefs[i][j] if i > 0 and status(buttons[i-1][j]) != "white": graph_node[node_key][f"{i-1}|{j}"] = coefs[i][j] if j < 14 and status(buttons[i][j+1]) != "white": graph_node[node_key][f"{i}|{j+1}"] = coefs[i][j] if j > 0 and status(buttons[i][j-1]) != "white": graph_node[node_key][f"{i}|{j-1}"] = coefs[i][j] elif btn_status == "black": graph_node[node_key] = {} finish_node = node_key else: coefs[i][j] = 10**100 if not start_node or not finish_node: print("请先设置起点(黄色)和终点(黑色)") return distance, predecessors, sh_len, sh_pth, path = dijkstra(graph_node, start_node, finish_node) print(sh_pth) # 高亮路径 for node in path: i, j = map(int, node.split('|')) btn = buttons[i][j] if btn.cget('background') not in ["yellow", "black"]: btn.config(bg="blue")
4. 状态判断函数补全
原status函数未处理按钮初始背景色,导致未点击的按钮无法被正确识别:
def status(btn): bg = btn.cget('background') if bg == 'yellow': return "yellow" elif bg == 'green': return "green" elif bg == 'black': return "black" elif bg == 'orange': return "orange" elif bg == 'red': return "red" else: return "white"
修复后完整代码
import sys sys.tracebacklimit = 0 import tkinter as tk import random as rd import heapq def dijkstra(graph, start, finish): distances = {node: float('infinity') for node in graph} distances[start] = 0 predecessors = {node: None for node in graph} priority_queue = [(0, start)] while priority_queue: current_distance, current_node = heapq.heappop(priority_queue) if current_distance > distances[current_node]: continue for neighbor, weight in graph[current_node].items(): distance = current_distance + weight if distance < distances[neighbor]: distances[neighbor] = distance predecessors[neighbor] = current_node heapq.heappush(priority_queue, (distance, neighbor)) path = [] current_node = finish while current_node is not None: path.insert(0, current_node) current_node = predecessors[current_node] sh = f"从{start}到{finish}的最短路径长度: {distances[finish]}" sh_pth = f"从{start}到{finish}的最短路径: {' -> '.join(path)}" return distances, predecessors, sh, sh_pth, path d1=1.675 #车辆平均宽度 D1=14 #车轮平均宽度 d2=4.875 #车辆平均长度 D2=100 #单位道路长度(自定义) a=1 #车辆侧向平均间距 b=5 #车辆纵向平均间距 #手动计算得出最大平均车辆数为52 def p(n): return(n*((d1+a)*(d2+b))/(D1*D2)) def status(btn): bg = btn.cget('background') if bg == 'yellow': return "yellow" elif bg == 'green': return "green" elif bg == 'black': return "black" elif bg == 'orange': return "orange" elif bg == 'red': return "red" else: return "white"
相关产品推荐
相关产品推荐

