[Python] Same size of text-labels and buttons

Discussão em 'Python' iniciado por Stack, Abril 20, 2025.

  1. Stack

    Stack Membro Participativo

    I am not really a programmer. I asked an AI to generate a matrix of buttons, with rows and columns having text-labels on top and left side of the window. I wanted the matrix to be scrollable but the labels on top/left should always remain visible. The code the AI gave me is actually doing what I described (sort of), but the scrolling somehow displaces the positions of labels and buttons, so that they are not really on the right spot if you scroll too much. It seems to me that the sizes of the label-texts and buttons are not exactly the same size? Does any one have an idea what is this not working well in the code of AI (oh, and also when I run the script, first nothing is visible on the main window!):

    import tkinter as tk

    class ScrollableMatrix:
    def __init__(self, root, rows=20, cols=30):
    self.root = root
    self.rows = rows
    self.cols = cols
    self.font = ('TkDefaultFont', 10) # Common font for all elements

    # Create main container
    self.container = tk.Frame(root)
    self.container.pack(fill="both", expand=True)

    # Create dummy widget to calculate sizes
    self._init_size_constants()

    # Create canvas widgets
    self.top_header_canvas = tk.Canvas(self.container, height=self.row_height)
    self.left_header_canvas = tk.Canvas(self.container, width=self.col_width)
    self.main_canvas = tk.Canvas(self.container)

    # Create scrollbars
    self.h_scroll = tk.Scrollbar(self.container, orient="horizontal")
    self.v_scroll = tk.Scrollbar(self.container, orient="vertical")

    # Grid layout configuration
    self.top_header_canvas.grid(row=0, column=1, sticky="ew")
    self.left_header_canvas.grid(row=1, column=0, sticky="ns")
    self.main_canvas.grid(row=1, column=1, sticky="nsew")
    self.v_scroll.grid(row=1, column=2, sticky="ns")
    self.h_scroll.grid(row=2, column=1, sticky="ew")

    # Configure grid weights
    self.container.grid_rowconfigure(1, weight=1)
    self.container.grid_columnconfigure(1, weight=1)

    # Create internal frames
    self.top_header_frame = tk.Frame(self.top_header_canvas)
    self.left_header_frame = tk.Frame(self.left_header_canvas)
    self.main_frame = tk.Frame(self.main_canvas)

    # Add frames to canvases
    self.top_header_canvas.create_window((0, 0), window=self.top_header_frame, anchor="nw")
    self.left_header_canvas.create_window((0, 0), window=self.left_header_frame, anchor="nw")
    self.main_canvas.create_window((0, 0), window=self.main_frame, anchor="nw")

    # Configure scroll commands
    self.main_canvas.configure(
    xscrollcommand=self._sync_main_x,
    yscrollcommand=self._sync_main_y
    )
    self.h_scroll.configure(command=self._sync_h_scroll)
    self.v_scroll.configure(command=self._sync_v_scroll)

    # Bind configuration events
    self.main_frame.bind("<Configure>", self._on_main_configure)
    self.top_header_frame.bind("<Configure>", self._on_top_header_configure)
    self.left_header_frame.bind("<Configure>", self._on_left_header_configure)

    # Create matrix elements
    self._create_labels_and_buttons()

    # Configure uniform column/row sizes
    self._configure_uniform_sizing()

    def _init_size_constants(self):
    """Calculate size constants using dummy widgets"""
    dummy_frame = tk.Frame(self.root)

    # Create dummy button
    dummy_btn = tk.Button(dummy_frame, text="X", font=self.font,
    width=10, height=2)
    dummy_btn.grid(row=0, column=0)

    # Create dummy label
    dummy_lbl = tk.Label(dummy_frame, text="X", font=self.font,
    width=10, height=2)
    dummy_lbl.grid(row=1, column=0)

    # Force geometry calculation
    dummy_frame.update_idletasks()

    # Get dimensions
    self.col_width = dummy_btn.winfo_width()
    self.row_height = dummy_btn.winfo_height()

    # Verify label matches button size
    lbl_width = dummy_lbl.winfo_width()
    lbl_height = dummy_lbl.winfo_height()

    if lbl_width != self.col_width or lbl_height != self.row_height:
    self.col_width = max(self.col_width, lbl_width)
    self.row_height = max(self.row_height, lbl_height)

    dummy_frame.destroy()

    def _create_labels_and_buttons(self):
    # Create column headers
    for j in range(self.cols):
    lbl = tk.Label(self.top_header_frame, text=f"Col {j+1}",
    font=self.font, width=10, height=2,
    relief="ridge", borderwidth=2, bg="red")
    lbl.grid(row=0, column=j, sticky="nsew")

    # Create row headers
    for i in range(self.rows):
    lbl = tk.Label(self.left_header_frame, text=f"Row {i+1}",
    font=self.font, width=10, height=2,
    relief="ridge", borderwidth=2, bg="red")
    lbl.grid(row=i, column=0, sticky="nsew")

    # Create buttons in main grid
    for i in range(self.rows):
    for j in range(self.cols):
    btn = tk.Button(self.main_frame, text=f"({i+1},{j+1})",
    font=self.font, width=10, height=2,
    relief="groove", borderwidth=2)
    btn.grid(row=i, column=j, sticky="nsew")

    def _configure_uniform_sizing(self):
    """Set uniform column widths and row heights"""
    for j in range(self.cols):
    self.main_frame.columnconfigure(j, minsize=self.col_width, weight=1)
    self.top_header_frame.columnconfigure(j, minsize=self.col_width, weight=1)

    for i in range(self.rows):
    self.main_frame.rowconfigure(i, minsize=self.row_height, weight=1)
    self.left_header_frame.rowconfigure(i, minsize=self.row_height, weight=1)

    def _sync_h_scroll(self, *args):
    self.main_canvas.xview(*args)
    self.top_header_canvas.xview(*args)

    def _sync_v_scroll(self, *args):
    self.main_canvas.yview(*args)
    self.left_header_canvas.yview(*args)

    def _sync_main_x(self, first, last):
    self.h_scroll.set(first, last)
    self.top_header_canvas.xview_moveto(first)

    def _sync_main_y(self, first, last):
    self.v_scroll.set(first, last)
    self.left_header_canvas.yview_moveto(first)

    def _on_main_configure(self, event):
    self.main_canvas.configure(scrollregion=self.main_canvas.bbox("all"))

    def _on_top_header_configure(self, event):
    self.top_header_canvas.configure(scrollregion=self.top_header_canvas.bbox("all"))

    def _on_left_header_configure(self, event):
    self.left_header_canvas.configure(scrollregion=self.left_header_canvas.bbox("all"))

    if __name__ == "__main__":
    root = tk.Tk()
    root.title("Uniform Size Matrix")
    root.geometry("800x600")

    matrix = ScrollableMatrix(root, rows=50, cols=50)

    root.mainloop()

    Continue reading...

Compartilhe esta Página