6,052
社区成员
发帖
与我相关
我的任务
分享
在完成数据结构课设(生成校园导航系统)过程中,发现电脑里同时有3.13和3.12版本的python,并遇到问题:
使用3.12作为解释器可以跑出代码,但是想进一步使用pillow库遇到困难(+选项无法使用,即无法加载新的库)
使用3.13作为解释器显示无法打开Tcl,应该是Tkinter出错,可以使用+,但是找不到tkinter库
如有大佬解答,鄙人感激万分,也希望您可以理解我在这方面知识的欠缺。
如果可以,也请指出相关背景知识,以供鄙人查缺补漏
附录(源码):
#主要依靠AI生成,欢迎提出批评建议
import tkinter as tk import heapq from typing import Dict, List, Tuple, Optional # 定义地点和位置 LOCATIONS = { "": (600, 80), } # 初始图 EDGES = { "": { "": 320}, } # 地点详细信息 LOCATIONS_INFO = { ": "", } # Dijkstra算法实现 def dijkstra(graph: Dict[str, Dict[str, float]], start: str, end: str) -> Tuple[float, list]: queue = [(0, start)] distances: Dict[str, float] = {node: float('inf') for node in graph} distances[start] = 0 previous_nodes: Dict[str, Optional[str]] = {node: None for node in graph} while queue: current_distance, current_node = heapq.heappop(queue) if current_node == end: break # 找到目标节点,提前结束 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 previous_nodes[neighbor] = current_node heapq.heappush(queue, (distance, neighbor)) path = [] current_node = end while current_node is not None: path.append(current_node) current_node = previous_nodes[current_node] path.reverse() return distances[end], path class CampusNavigator(tk.Tk): def __init__(self): super().__init__() self.title("扬子津校园导航") # 设置窗口标题 self.geometry("800x600")# 设置窗口大小 self.canvas = tk.Canvas(self, bg="white")# 创建一个白色背景画布,并填充整个窗口。 self.canvas.pack(fill=tk.BOTH, expand=True) # 初始化变量:缩放级别、偏移量、信息文本。 self.zoom_level = 1.0 self.offset_x = 0 self.offset_y = 0 self.info_text = None # 起始和目标地点的输入框 self.start_entry = tk.Entry(self) self.start_entry.pack(pady=10) self.start_entry.insert(0, "请输入起点,如:西门") self.end_entry = tk.Entry(self) self.end_entry.pack(pady=10) self.end_entry.insert(0, "请输入终点,如:东操场") # 距离设置输入框 self.distance_entry = tk.Entry(self) self.distance_entry.pack(pady=10) self.distance_entry.insert(0, "请输入距离(m)如:200") self.set_distance_button = tk.Button(self, text="设置距离", command=self.set_distance) self.set_distance_button.pack(pady=5) # 设置计算最短路径选项按钮 self.calc_button = tk.Button(self, text="计算最短路径", command=self.calculate_shortest_path) self.calc_button.pack(pady=10) self.last_path_lines = [] # 用于保存上一次路径的线条 # 绑定鼠标事件(拖拽、放缩的开始和终止) self.canvas.bind("<ButtonPress-1>", self.start_drag) self.canvas.bind("<B1-Motion>", self.drag) self.canvas.bind("<ButtonRelease-1>", self.end_drag) self.canvas.bind("<MouseWheel>", self.zoom) self.canvas.bind("<Motion>", self.on_mouse_move) # 绘制地图(循环调用以实现实时更新) self.draw_map() def draw_map(self): self.canvas.delete("all")# 清除画布上的全部内容 # 绘制建筑物 for location, (x, y) in LOCATIONS.items(): #使用 坐标*放大倍数+偏移量 的公式来实现拖拽、放缩功能 scaled_x = x * self.zoom_level + self.offset_x scaled_y = y * self.zoom_level + self.offset_y self.canvas.create_rectangle(scaled_x - 5, scaled_y - 5, scaled_x + 5, scaled_y + 5, fill="blue", tags=location) self.canvas.create_text(scaled_x, scaled_y - 10, text=location, fill="black", tags="label") # 绘制连接线和距离 for loc1, edges in EDGES.items(): for loc2, distance in edges.items(): x1, y1 = LOCATIONS[loc1] x2, y2 = LOCATIONS[loc2] # 绘制连接线 self.canvas.create_line(x1 * self.zoom_level + self.offset_x, y1 * self.zoom_level + self.offset_y, x2 * self.zoom_level + self.offset_x, y2 * self.zoom_level + self.offset_y, fill="lightgray") # 计算中点位置(为了显示距离) mid_x = (x1 + x2) / 2 * self.zoom_level + self.offset_x mid_y = (y1 + y2) / 2 * self.zoom_level + self.offset_y # 在中点位置显示距离 self.canvas.create_text(mid_x, mid_y, text=str(distance), fill="purple") def set_distance(self): start_location = self.start_entry.get().strip() #从输入框获取起点、终点和距离。 end_location = self.end_entry.get().strip() distance = self.distance_entry.get().strip() if start_location in LOCATIONS and end_location in LOCATIONS:# 检查起点和终点是否有效,并尝试将距离转换为浮点数。 try: distance_value = float(distance)# 如果距离有效,更新 EDGES 字典中的距离 if distance_value == 0: # 如果设置为0,则删除该线路 if end_location in EDGES[start_location]: del EDGES[start_location][end_location] if start_location in EDGES[end_location]: del EDGES[end_location][start_location] self.show_message(f"已删除从 {start_location} 到 {end_location} 的线路。") # 显示操作结果信息 else: # 更新图的距离 EDGES[start_location][end_location] = distance_value EDGES[end_location][start_location] = distance_value # 由于是无向图,反向也要更新 self.show_message(f"已设置从 {start_location} 到 {end_location} 的距离为 {distance_value}。") except ValueError: self.show_message("请输入有效的距离!") else: self.show_message("起点或终点无效!") # 重新绘制地图以更新状态 self.draw_map() def calculate_shortest_path(self): start_location = self.start_entry.get().strip() end_location = self.end_entry.get().strip() if start_location in LOCATIONS and end_location in LOCATIONS: # 获取最短路径和距离 distance, path = dijkstra(EDGES, start_location, end_location) # 恢复上一次路径的颜色 for line in self.last_path_lines: self.canvas.itemconfig(line, fill="lightgray") # 绘制新的最短路径并保存线条 self.last_path_lines = [] for i in range(len(path) - 1): loc1 = path[i] loc2 = path[i + 1] x1, y1 = LOCATIONS[loc1] x2, y2 = LOCATIONS[loc2] line = self.canvas.create_line(x1 * self.zoom_level + self.offset_x, y1 * self.zoom_level + self.offset_y, x2 * self.zoom_level + self.offset_x, y2 * self.zoom_level + self.offset_y, fill="red") # 设为红色 self.last_path_lines.append(line) # 保存新的线条 result_text = f"从 {start_location} 到 {end_location} 的最短路径为:{' -> '.join(path)}\n距离: {distance} 单位" if hasattr(self, 'result_label'): self.result_label.destroy() self.result_label = tk.Label(self, text=result_text, bg="white") self.result_label.pack(pady=10) else: # 处理无效的地点名 if hasattr(self, 'result_label'): self.result_label.destroy() self.result_label = tk.Label(self, text="请输入有效的地点名!", bg="white") self.result_label.pack(pady=10) def show_message(self, message: str): if hasattr(self, 'message_label'): self.message_label.destroy() self.message_label = tk.Label(self, text=message, bg="white") self.message_label.pack(pady=5) def on_mouse_move(self, event): closest_location = None #赋初值 closest_distance = float('inf') for loc, (x, y) in LOCATIONS.items(): #定义鼠标悬停的距离,以便显示用户指向的地点信息 scaled_x = x * self.zoom_level + self.offset_x scaled_y = y * self.zoom_level + self.offset_y distance = ((event.x - scaled_x) ** 2 + (event.y - scaled_y) ** 2) ** 0.5 if distance < 15: # 设定鼠标悬停的距离阈值 closest_location = loc break if closest_location: self.display_info(closest_location) else: self.clear_info() #防止地点信息始终显示 def display_info(self, location: str): if self.info_text: self.clear_info() # 获取地点的详细信息(包括内容和位置) info = LOCATIONS_INFO.get(location, "无详细信息") x, y = LOCATIONS[location] text_x = x * self.zoom_level + self.offset_x #保证始终显示在地点旁边 text_y = y * self.zoom_level + self.offset_y # 在画布上显示地点信息 self.info_text = self.canvas.create_text(text_x, text_y + 15, text=info, fill="purple") def clear_info(self): if self.info_text: self.canvas.delete(self.info_text) self.info_text = None # 重置信息文本变量 def start_drag(self, event): self.last_x = event.x self.last_y = event.y def drag(self, event): dx = event.x - self.last_x dy = event.y - self.last_y self.offset_x += dx self.offset_y += dy self.last_x = event.x self.last_y = event.y self.draw_map() def end_drag(self, event): pass # 释放鼠标时可以在这里添加任何需要的操作 ########################################################### def zoom(self, event): if event.delta > 0: self.zoom_level *= 1.1 else: self.zoom_level /= 1.1 self.draw_map() if __name__ == "__main__": app = CampusNavigator() #创建类的实例 app.mainloop() #进入应用的主循环,等待用户触发事件