可能因版本冲突在Pycharm中使用tkinter和pillow库遇到困难

qq_39679212 2024-11-26 16:43:09

在完成数据结构课设(生成校园导航系统)过程中,发现电脑里同时有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()    #进入应用的主循环,等待用户触发事件
...全文
46 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

6,052

社区成员

发帖
与我相关
我的任务
社区描述
人生苦短,我用python
社区管理员
  • Python 学习者
  • 嗨学编程
  • 松鼠爱吃饼干
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

欢迎来到Python学习者们的社区,

 

本社区分享你需要的文章、问题解答、技术互助、学习资源、面试系列等等

 

欢迎你的加入,祝你学有所成~

试试用AI创作助手写篇文章吧