Tkinter 滚动条问题

问题描述 投票:0回答:2

请有人帮我修复滚动条,并为第三个画布添加滚动条。 实际上我已经创建了数据结构可视化工具。面对滚动条,目前我无法滚动到第三个画布。 语言-pyhton

import tkinter as tk
from tkinter import ttk, messagebox
import matplotlib.pyplot as plt
import time

class VisualizerApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Data Structure and Sorting Algorithm")
        self.root.geometry("1200x800")

        # Canvas for the Main Window
        self.canvas = tk.Canvas(root)
        self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

        # Scrollbars for the main window
        self.scroll_x = tk.Scrollbar(root, orient=tk.HORIZONTAL, command=self.canvas.xview)
        self.scroll_x.pack(side=tk.BOTTOM, fill=tk.X)
        self.scroll_y = tk.Scrollbar(root, orient=tk.VERTICAL, command=self.canvas.yview)
        self.scroll_y.pack(side=tk.RIGHT, fill=tk.Y)

        # Frame for the widgets
        self.frame = tk.Frame(self.canvas)
        self.canvas.create_window((0, 0), window=self.frame, anchor='nw')

        # Configure Canvas scrolling
        self.frame.bind("<Configure>", self.on_frame_configure)
        self.canvas.config(xscrollcommand=self.scroll_x.set, yscrollcommand=self.scroll_y.set)

        # Setup UI
        self.setup_ui()

    def setup_ui(self):
        # Frame for data structure selection and visualization
        self.data_frame = tk.Frame(self.frame)
        self.data_frame.pack(padx=10, pady=10, fill=tk.BOTH, expand=True)

        # Dropdown menus for data structures
        tk.Label(self.data_frame, text="Select Data Structure:", fg="black").pack(padx=10, pady=5, anchor=tk.W)
        options = ["Array", "Stack", "Linked List", "Set", "Tuple", "Dictionary"]
        self.data_structure = tk.StringVar(value=options[0])
        data_structure_menu = tk.OptionMenu(self.data_frame, self.data_structure, *options)
        data_structure_menu.pack(padx=10, pady=5, anchor=tk.W)

        # Entry for the values
        tk.Label(self.data_frame, text="Enter Values (Comma Separated):", fg="black").pack(padx=10, pady=5, anchor=tk.W)
        self.data_entry = tk.Entry(self.data_frame)
        self.data_entry.pack(padx=10, pady=5, anchor=tk.W)

        # Canvas for visualizing data structures
        self.canvas_data_structure = tk.Canvas(self.data_frame, bg="white", width=1000, height=300)
        self.canvas_data_structure.pack(padx=10, pady=5, fill=tk.BOTH, expand=True)

        # Scrollbars for data structure canvas
        self.scroll_x_data = tk.Scrollbar(self.data_frame, orient=tk.HORIZONTAL, command=self.canvas_data_structure.xview)
        self.scroll_x_data.pack(side=tk.BOTTOM, fill=tk.X)
        self.canvas_data_structure.config(xscrollcommand=self.scroll_x_data.set)

        self.scroll_y_data = tk.Scrollbar(self.data_frame, orient=tk.VERTICAL, command=self.canvas_data_structure.yview)
        self.scroll_y_data.pack(side=tk.RIGHT, fill=tk.Y)
        self.canvas_data_structure.config(yscrollcommand=self.scroll_y_data.set)

        # Button for visualizing data structure
        self.visualize_button = tk.Button(self.data_frame, text="Visualize Data Structure", command=self.visualize_data_structure)
        self.visualize_button.pack(padx=10, pady=5)

        # Frame for sorting algorithm selection and visualization
        self.sort_frame = tk.Frame(self.frame)
        self.sort_frame.pack(padx=10, pady=10, fill=tk.BOTH, expand=True)

        # Dropdown menu for sorting algorithms
        tk.Label(self.sort_frame, text="Select Sorting Algorithm:", fg="black").pack(padx=10, pady=5, anchor=tk.W)
        options2 = ["Bubble Sort", "Insertion Sort", "Quick Sort"]
        self.sorting_algos = tk.StringVar(value=options2[0])
        sorting_algorithm_menu = tk.OptionMenu(self.sort_frame, self.sorting_algos, *options2)
        sorting_algorithm_menu.pack(padx=10, pady=5, anchor=tk.W)

        # Button for sort and visualize
        self.sort_button = tk.Button(self.sort_frame, text="Sort and Visualize", command=self.sort_and_visualize)
        self.sort_button.pack(padx=10, pady=5)

        # Frame and canvas for sorting visualization
        self.sorting_canvas_frame = tk.Frame(self.sort_frame)
        self.sorting_canvas_frame.pack(padx=10, pady=5, fill=tk.BOTH, expand=True)

        self.canvas_sorting = tk.Canvas(self.sorting_canvas_frame, bg="white", width=1000, height=300)
        self.canvas_sorting.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

        # Scrollbars for sorting canvas
        self.scroll_x_sort = tk.Scrollbar(self.sorting_canvas_frame, orient=tk.HORIZONTAL, command=self.canvas_sorting.xview)
        self.scroll_x_sort.pack(side=tk.BOTTOM, fill=tk.X)
        self.canvas_sorting.config(xscrollcommand=self.scroll_x_sort.set)

        self.scroll_y_sort = tk.Scrollbar(self.sorting_canvas_frame, orient=tk.VERTICAL, command=self.canvas_sorting.yview)
        self.scroll_y_sort.pack(side=tk.RIGHT, fill=tk.Y)
        self.canvas_sorting.config(yscrollcommand=self.scroll_y_sort.set)

        # Text area for the explanation
        self.explanation_frame = tk.Frame(self.frame)
        self.explanation_frame.pack(padx=10, pady=10, fill=tk.BOTH, expand=True)

        self.explanation_text = tk.Text(self.explanation_frame, height=10, width=100)
        self.explanation_text.pack(padx=10, pady=5, fill=tk.BOTH, expand=True)

    def on_frame_configure(self, event):
        self.canvas.config(scrollregion=self.canvas.bbox("all"))
        self.canvas_data_structure.config(scrollregion=self.canvas_data_structure.bbox("all"))
        self.canvas_sorting.config(scrollregion=self.canvas_sorting.bbox("all"))

    def visualize_data_structure(self):
        data_type = self.data_structure.get()
        values = self.data_entry.get()

        if not data_type or not values:
            messagebox.showerror("Input Error", "Please select a data structure and enter values")
            return
        
        try:
            self.data = list(map(int, values.split(',')))
        except ValueError:
            messagebox.showerror("Input Error", "Please enter valid integer values.")
            return
        
        if data_type == "Array" or data_type == "Tuple":
            self.draw_array(self.data, self.canvas_data_structure)
        elif data_type == "Stack":
            self.draw_stack(self.data, self.canvas_data_structure)
        elif data_type == "Linked List":
            self.draw_linked_list(self.data, self.canvas_data_structure)
        elif data_type == "Set":
            self.draw_set(set(self.data), self.canvas_data_structure)
        elif data_type == "Dictionary":
            self.draw_dictionary({i: val for i, val in enumerate(self.data)}, self.canvas_data_structure)

    def draw_array(self, data, canvas, color_array=None):
        canvas.delete("all")
        canvas_height = 180
        canvas_width = max(800, len(data) * 100)
        bar_width = canvas_width / (len(data) + 1)
        bar_height = 40
        bar_width = 60
        offset = 30
        spacing = 10

        if color_array is None:
            color_array = ["red" for _ in data]

        for i, height in enumerate(data):
            x0 = i * (bar_width + spacing)+offset
            y0 = canvas_height//2 - bar_height//2
            x1 = x0 + bar_width
            y1 = y0 + bar_height
            
            color = color_array[i]
            canvas.create_rectangle(x0, y0, x1, y1, fill=color)
            canvas.create_text((x0 + x1) // 2, (y0 + y1) // 2, text=str(height), fill="white")

        canvas.config(scrollregion=canvas.bbox("all"))
        self.root.update_idletasks()

    def draw_stack(self, data, canvas):
        canvas.delete("all")
        canvas_height = 180
        canvas_width = 80
        bar_width = 60
        offset = 30
        spacing = 10
        
        for i, height in enumerate(data):
            x0 = offset
            y0 = canvas_height - (i + 1) * (bar_width + spacing)
            x1 = offset + bar_width
            y1 = canvas_height - i * (bar_width + spacing)
            
            canvas.create_rectangle(x0, y0, x1, y1, fill="blue")
            canvas.create_text((x0 + x1) // 2, (y0 + y1) // 2, text=str(height), fill="white")
        
        canvas.config(scrollregion=canvas.bbox("all"))
        self.root.update_idletasks()

    def draw_linked_list(self, data, canvas):
        canvas.delete("all")
        canvas_height = 180
        canvas_width = max(800, len(data) * 100)
        bar_width = canvas_width / (len(data) + 1)
        node_width=60
        node_height = 40
        offset = 30
        spacing = 40

        for i, value in enumerate(data):
            x0 = i * (node_width + spacing) + offset
            y0 = canvas_height // 2 - node_height // 2
            x1 = x0 + node_width
            y1 = y0 + node_height
            
            canvas.create_rectangle(x0, y0, x1, y1, fill="green")
            canvas.create_text((x0 + x1) // 2, (y0 + y1) // 2, text=str(value), fill="white")
            if i < len(data) - 1:
                x2 = x1 + spacing // 2
                y2 = canvas_height // 2
                x3 = x1 + spacing
                canvas.create_line(x1, y2, x2, y2, arrow=tk.LAST, fill="black")

        canvas.config(scrollregion=canvas.bbox("all"))
        self.root.update_idletasks()

    def draw_set(self, data, canvas):
        canvas.delete("all")
        canvas_height = 180
        canvas_width = max(800, len(data) * 100)
        bar_width = canvas_width / (len(data) + 1)
        bar_height = 40
        bar_width = 60
        offset = 30
        spacing = 10

        for i, value in enumerate(data):
            x0 = i * (bar_width + spacing)+offset
            y0 = canvas_height//2 - bar_height//2
            x1 = x0 + bar_width
            y1 = y0 + bar_height
            
            canvas.create_rectangle(x0, y0, x1, y1, fill="purple")
            canvas.create_text((x0 + x1) // 2, (y0 + y1) // 2, text=str(value), fill="white")

        canvas.config(scrollregion=canvas.bbox("all"))
        self.root.update_idletasks()

    def draw_dictionary(self, data, canvas):
        canvas.delete("all")
        canvas_height = 180
        canvas_width = max(800, len(data) * 100)
        bar_width = canvas_width / (len(data) + 1)
        bar_height = 40
        bar_width = 60
        offset = 30
        spacing = 10

        for i, (key, value) in enumerate(data.items()):
            x0 = i * (bar_width + spacing)+offset
            y0 = canvas_height//2 - bar_height//2
            x1 = x0 + bar_width
            y1 = y0 + bar_height
            
            canvas.create_rectangle(x0, y0, x1, y1, fill="orange")
            canvas.create_text((x0 + x1) // 2, (y0 + y1) // 2 - 10, text=str(key), fill="white")
            canvas.create_text((x0 + x1) // 2, (y0 + y1) // 2 + 10, text=str(value), fill="white")

        canvas.config(scrollregion=canvas.bbox("all"))
        self.root.update_idletasks()

    def sort_and_visualize(self):
        sorting_algo = self.sorting_algos.get()
        values = self.data_entry.get()

        if not sorting_algo or not values:
            messagebox.showerror("Input Error", "Please select a sorting algorithm and enter values")
            return
        
        try:
            self.data = list(map(int, values.split(',')))
        except ValueError:
            messagebox.showerror("Input Error", "Please enter valid integer values.")
            return

        if sorting_algo == "Bubble Sort":
            self.bubble_sort(self.data)
        elif sorting_algo == "Insertion Sort":
            self.insertion_sort(self.data)
        elif sorting_algo == "Quick Sort":
            self.quick_sort(self.data, 0, len(self.data) - 1)

    def bubble_sort(self, data):
        self.explanation_text.delete("1.0", tk.END)
        self.explanation_text.insert(tk.END, "Bubble Sort Explanation:\n\n")
        
        n = len(data)
        for i in range(n):
            for j in range(0, n - i - 1):
                if data[j] > data[j + 1]:
                    data[j], data[j + 1] = data[j + 1], data[j]
                    self.draw_array(data, self.canvas_sorting, ["green" if x == data[j] else "red" if x == data[j+1] else "gray" for x in data])
                    self.explanation_text.insert(tk.END, f"Swapped {data[j+1]} and {data[j]}\n")
                    self.root.update()
                    time.sleep(1)
                    
        self.draw_array(data, self.canvas_sorting, ["green" for _ in data])

    def insertion_sort(self, data):
        self.explanation_text.delete("1.0", tk.END)
        self.explanation_text.insert(tk.END, "Insertion Sort Explanation:\n\n")
        
        for i in range(1, len(data)):
            key = data[i]
            j = i - 1
            while j >= 0 and key < data[j]:
                data[j + 1] = data[j]
                j -= 1
                self.draw_array(data, self.canvas_sorting, ["green" if x == key else "red" if x == data[j+1] else "gray" for x in data])
                self.explanation_text.insert(tk.END, f"Moved {data[j+1]} to position {j+2}\n")
                self.root.update()
                time.sleep(1)
            data[j + 1] = key
            self.draw_array(data, self.canvas_sorting, ["green" if x == key else "gray" for x in data])
            self.explanation_text.insert(tk.END, f"Inserted {key} at position {j+1}\n")

        self.draw_array(data, self.canvas_sorting, ["green" for _ in data])

    def quick_sort(self, data, low, high):
        if low < high:
            pi = self.partition(data, low, high)
            self.quick_sort(data, low, pi - 1)
            self.quick_sort(data, pi + 1, high)

    def partition(self, data, low, high):
        self.explanation_text.delete("1.0", tk.END)
        self.explanation_text.insert(tk.END, "Quick Sort Explanation:\n\n")
        
        i = low - 1
        pivot = data[high]

        for j in range(low, high):
            if data[j] < pivot:
                i += 1
                data[i], data[j] = data[j], data[i]
                self.draw_array(data, self.canvas_sorting, ["green" if x == pivot else "red" if x == data[i] else "gray" for x in data])
                self.explanation_text.insert(tk.END, f"Swapped {data[i]} with {data[j]}\n")
                self.root.update()
                time.sleep(1)

        data[i + 1], data[high] = data[high], data[i + 1]
        self.draw_array(data, self.canvas_sorting, ["green" if x == pivot else "red" if x == data[i+1] else "gray" for x in data])
        self.explanation_text.insert(tk.END, f"Moved pivot {pivot} to correct position\n")

        return i + 1

if __name__ == "__main__":
    root = tk.Tk()
    app = VisualizerApp(root)
    root.mainloop()

我期待主窗口有一个滚动条,可以滚动所有画布,还有第三个画布的滚动条。

python tkinter visualization tkinter-canvas
2个回答
1
投票

在运行之前将所有三个根包移至末尾。

    self.scroll_y.pack(side=tk.RIGHT, fill=tk.Y)
    self.scroll_x.pack(side=tk.BOTTOM, fill=tk.X)
    self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

def on_frame_configure(self, event):

您无法垂直和水平滚动。除非你在 Canvas 中添加小部件。

更改垂直和水平方向:

tk.Scrollbar(self.data_frame,

至:

tk.Scrollbar(self.canvas_data_structure,

还有这个:

tk.Scrollbar(self.sorting_canvas_frame,

至:

tk.Scrollbar(self.canvas_sorting 

仅在调整大小时截图:

enter image description here


0
投票

代表canvas_sorting的第三个画布的滚动条应该配置为在所有画布之间正确滚动。更具体地说,我们需要执行以下操作:

为名为canvas_sorting的第三个画布配置滚动条。 确保所有滚动条都正确绑定到各自的画布。

将在下面的代码中进行更改以实现这些。

将 tkinter 导入为 tk 从 tkinter 导入 ttk、消息框 将 matplotlib.pyplot 导入为 plt 导入时间

VisualizerApp 类: def init(自身,根): self.root = 根 self.root.title("数据结构与排序算法") self.root.geometry("1200x800")

    # Canvas for the Main Window
    self.canvas = tk.Canvas(root)
    self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

    # Scrollbars for the main window
    self.scroll_x = tk.Scrollbar(root, orient=tk.HORIZONTAL, command=self.canvas.xview)
    self.scroll_x.pack(side=tk.BOTTOM, fill=tk.X)
    self.scroll_y = tk.Scrollbar(root, orient=tk.VERTICAL, command=self.canvas.yview)
    self.scroll_y.pack(side=tk.RIGHT, fill=tk.Y)

    # Frame for the widgets
    self.frame = tk.Frame(self.canvas)
    self.canvas.create_window((0, 0), window=self.frame, anchor='nw')

    # Configure Canvas scrolling
    self.frame.bind("<Configure>", self.on_frame_configure)
    self.canvas.config(xscrollcommand=self.scroll_x.set, yscrollcommand=self.scroll_y.set)

    # Setup UI
    self.setup_ui()

def setup_ui(self):
    # Frame for data structure selection and visualization
    self.data_frame = tk.Frame(self.frame)
    self.data_frame.pack(padx=10, pady=10, fill=tk.BOTH, expand=True)

    # Dropdown menus for data structures
    tk.Label(self.data_frame, text="Select Data Structure:", fg="black").pack(padx=10, pady=5, anchor=tk.W)
    options = ["Array", "Stack", "Linked List", "Set", "Tuple", "Dictionary"]
    self.data_structure = tk.StringVar(value=options[0])
    data_structure_menu = tk.OptionMenu(self.data_frame, self.data_structure, *options)
    data_structure_menu.pack(padx=10, pady=5, anchor=tk.W)

    # Entry for the values
    tk.Label(self.data_frame, text="Enter Values (Comma Separated):", fg="black").pack(padx=10, pady=5, anchor=tk.W)
    self.data_entry = tk.Entry(self.data_frame)
    self.data_entry.pack(padx=10, pady=5, anchor=tk.W)

    # Canvas for visualizing data structures
    self.canvas_data_structure = tk.Canvas(self.data_frame, bg="white", width=1000, height=300)
    self.canvas_data_structure.pack(padx=10, pady=5, fill=tk.BOTH, expand=True)

    # Scrollbars for data structure canvas
    self.scroll_x_data = tk.Scrollbar(self.data_frame, orient=tk.HORIZONTAL, command=self.canvas_data_structure.xview)
    self.scroll_x_data.pack(side=tk.BOTTOM, fill=tk.X)
    self.canvas_data_structure.config(xscrollcommand=self.scroll_x_data.set)

    self.scroll_y_data = tk.Scrollbar(self.data_frame, orient=tk.VERTICAL, command=self.canvas_data_structure.yview)
    self.scroll_y_data.pack(side=tk.RIGHT, fill=tk.Y)
    self.canvas_data_structure.config(yscrollcommand=self.scroll_y_data.set)

    # Button for visualizing data structure
    self.visualize_button = tk.Button(self.data_frame, text="Visualize Data Structure", command=self.visualize_data_structure)
    self.visualize_button.pack(padx=10, pady=5)

    # Frame for sorting algorithm selection and visualization
    self.sort_frame = tk.Frame(self.frame)
    self.sort_frame.pack(padx=10, pady=10, fill=tk.BOTH, expand=True)

    # Dropdown menu for sorting algorithms
    tk.Label(self.sort_frame, text="Select Sorting Algorithm:", fg="black").pack(padx=10, pady=5, anchor=tk.W)
    options2 = ["Bubble Sort", "Insertion Sort", "Quick Sort"]
    self.sorting_algos = tk.StringVar(value=options2[0])
    sorting_algorithm_menu = tk.OptionMenu(self.sort_frame, self.sorting_algos, *options2)
    sorting_algorithm_menu.pack(padx=10, pady=5, anchor=tk.W)

    # Button for sort and visualize
    self.sort_button = tk.Button(self.sort_frame, text="Sort and Visualize", command=self.sort_and_visualize)
    self.sort_button.pack(padx=10, pady=5)

    # Frame and canvas for sorting visualization
    self.sorting_canvas_frame = tk.Frame(self.sort_frame)
    self.sorting_canvas_frame.pack(padx=10, pady=5, fill=tk.BOTH, expand=True)

    self.canvas_sorting = tk.Canvas(self.sorting_canvas_frame, bg="white", width=1000, height=300)
    self.canvas_sorting.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

    # Scrollbars for sorting canvas
    self.scroll_x_sort = tk.Scrollbar(self.sorting_canvas_frame, orient=tk.HORIZONTAL, command=self.canvas_sorting.xview)
    self.scroll_x_sort.pack(side=tk.BOTTOM, fill=tk.X)
    self.canvas_sorting.config(xscrollcommand=self.scroll_x_sort.set)

    self.scroll_y_sort = tk.Scrollbar(self.sorting_canvas_frame, orient=tk.VERTICAL, command=self.canvas_sorting.yview)
    self.scroll_y_sort.pack(side=tk.RIGHT, fill=tk.Y)
    self.canvas_sorting.config(yscrollcommand=self.scroll_y_sort.set)

    # Text area for the explanation
    self.explanation_frame = tk.Frame(self.frame)
    self.explanation_frame.pack(padx=10, pady=10, fill=tk.BOTH, expand=True)

    self.explanation_text = tk.Text(self.explanation_frame, height=10, width=100)
    self.explanation_text.pack(padx=10, pady=5, fill=tk.BOTH, expand=True)

def on_frame_configure(self, event):
    self.canvas.config(scrollregion=self.canvas.bbox("all"))
    self.canvas_data_structure.config(scrollregion=self.canvas_data_structure.bbox("all"))
    self.canvas_sorting.config(scrollregion=self.canvas_sorting.bbox("all"))

def visualize_data_structure(self):
    data_type = self.data_structure.get()
    values = self.data_entry.get()

    if not data_type or not values:
        messagebox.showerror("Input Error", "Please select a data structure and enter values")
        return
    
    try:
        self.data = list(map(int, values.split(',')))
    except ValueError:
        messagebox.showerror("Input Error", "Please enter valid integer values.")
        return
    
    if data_type == "Array" or data_type == "Tuple":
        self.draw_array(self.data, self.canvas_data_structure)
    elif data_type == "Stack":
        self.draw_stack(self.data, self.canvas_data_structure)
    elif data_type == "Linked List":
        self.draw_linked_list(self.data, self.canvas_data_structure)
    elif data_type == "Set":
        self.draw_set(set(self.data), self.canvas_data_structure)
    elif data_type == "Dictionary":
        self.draw_dictionary({i: val for i, val in enumerate(self.data)}, self.canvas_data_structure)

def draw_array(self, data, canvas, color_array=None):
    canvas.delete("all")
    canvas_height = 180
    canvas_width = max(800, len(data) * 100)
    bar_width = canvas_width / (len(data) + 1)
    bar_height = 40
    bar_width = 60
    offset = 30
    spacing = 10

    if color_array is None:
        color_array = ["red" for _ in data]

    for i, height in enumerate(data):
        x0 = i * (bar_width + spacing)+offset
        y0 = canvas_height//2 - bar_height//2
        x1 = x0 + bar_width
        y1 = y0 + bar_height
        
        color = color_array[i]
        canvas.create_rectangle(x0, y0, x1, y1, fill=color)
        canvas.create_text((x0 + x1) // 2, (y0 + y1) // 2, text=str(height), fill="white")

    canvas.config(scrollregion=canvas.bbox("all"))
    self.root.update_idletasks()

def draw_stack(self, data, canvas):
    canvas.delete("all")
    canvas_height = 180
    canvas_width = 80
    bar_width = 60
    offset = 30
    spacing = 10
    
    for i, height in enumerate(data):
        x0 = offset
        y0 = canvas_height - (i + 1) * (bar_width + spacing)
        x1 = offset + bar_width
        y1 = canvas_height - i * (bar_width + spacing)
        
        canvas.create_rectangle(x0, y0, x1, y1, fill="blue")
        canvas.create_text((x0 + x1) // 2, (y0 + y1) // 2, text=str(height), fill="white")
    
    canvas.config(scrollregion=canvas.bbox("all"))
    self.root.update_idletasks()

def draw_linked_list(self, data, canvas):
    canvas.delete("all")
    canvas_height = 180
    canvas_width = max(800, len(data) * 100)
    bar_width = canvas_width / (len(data) + 1)
    node_width=60
© www.soinside.com 2019 - 2024. All rights reserved.