You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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"

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 01:14:53