Tkinter Grid布局中columnspan破坏列均匀权重问题咨询
Tkinter Grid布局中columnspan与weight、uniform结合的异常问题
在使用CustomTkinter的Grid布局时,遇到columnspan属性与weight、uniform配置结合后的布局异常:当为两个表格组件设置columnspan=2时,它们会占用超出预期的空间,直接挤占了其他配置了uniform权重的列。按Grid布局的设计逻辑,在定义了uniform分组和weight权重后,网格单元格的大小应该由配置的规则决定,子组件不应强制修改,但设置columnspan后却出现了违背该逻辑的问题。
主类代码
import customtkinter as ctk import sql import pandas as pd from gui_elements import * class Menu_Window(ctk.CTk): def __init__(self, width = 1280, height = 720, version = '0.0.1'): super().__init__() self.geometry(f"{width}x{height}") self.protocol("WM_DELETE_WINDOW", self.destroy) self.rowconfigure((0, 7), weight=1, uniform='r') self.rowconfigure((1,2,3,4,6), weight=2, uniform='r') self.rowconfigure(5, weight=12, uniform='r') self.columnconfigure((0, 3, 6), weight=3, uniform='c') self.columnconfigure((1,2,4,5), weight=3, uniform='c') df_display = pd.DataFrame() df_display['Index'] = [0, 1, 2, 3, 4, 5, 6] df_display['Time'] = [0, 1, 2, 3, 4, 5, 6] df_display['A'] = [0, 1, 2, 3, 4, 5, 6] df_display['B'] = [0, 1, 2, 3, 4, 5, 6] df_display['C'] = [0, 1, 2, 3, 4, 5, 6] df_display['D'] = [0, 1, 2, 3, 4, 5, 6] #table = ctk.CTkFrame(self, fg_color='red') table = CTkTable(self, dataframe=df_display) table.grid(row=5, column=1, columnspan=2 ,sticky='nsew') #table2 = ctk.CTkFrame(self, fg_color='blue') table2 = CTkTable(self, dataframe=df_display) table2.grid(row=5, column=4, columnspan=2 ,sticky='nsew') if __name__ == '__main__': menu_window = Menu_Window() menu_window.mainloop()
表格类代码
import random import numpy as np import math import customtkinter as ctk class CTkTable(ctk.CTkFrame): def __init__(self, master, dataframe=None, view_bounds = [8, 5]): super().__init__(master, corner_radius=0) self.font_header = ("Book Antiqua", 12) self.font_data = ("Book Antiqua", 12) self.view_bounds = view_bounds if self.view_bounds[1] < 3: self.view_bounds[1] = 3 self.column_offset_max = -1 self.row_offset_max = -1 self.column_offset = 0 self.row_offset = 0 self.color = 'white' self.dataframe = dataframe self.headers = [] self.table_frame_array = [] self.frame_column_header_array = [] self.frame_column_header = ctk.CTkFrame(master=self, corner_radius=0) self.frame_column_time_header = ctk.CTkFrame(master=self, corner_radius=0) self.frame_column_index_header = ctk.CTkFrame(master=self, corner_radius=0) self.frame_table = ctk.CTkFrame(master=self, corner_radius=0) self.v_scroll = ctk.CTkSlider(master=self, orientation='vertical', command=lambda value: self.update_view(1-value, dir='row'), fg_color = self.color) self.v_scroll.set(1) self.h_scroll = ctk.CTkSlider(master=self, orientation='horizontal', command=lambda value: self.update_view(value, dir='col'), fg_color = self.color) self.h_scroll.set(0) self.button_settings = ctk.CTkButton(master=self, text='⚙', font=self.font_header, text_color='black', fg_color='gray', corner_radius=0) if self.dataframe is not None: self.selected_cols = self.dataframe.columns.tolist() self.selected_cols.remove('Time') self.selected_cols.remove('Index') self.setup_table_data() def setup_table_data(self): self.table_frame_array = [] self.frame_column_header_array = [] num_rows = min(len(self.dataframe[self.selected_cols[-1]]), self.view_bounds[0]) num_columns = min(len(self.selected_cols), self.view_bounds[1])-2 self.rowconfigure(0, weight = 2, uniform='r') self.rowconfigure(1, weight = 16, uniform='r') self.rowconfigure(2, weight = 1, uniform='r') z = lcm(num_columns+2, 19) x = z * (num_columns+2) / 19 self.columnconfigure(0, weight = int(z), uniform='c') self.columnconfigure(1, weight = int(z), uniform='c') self.columnconfigure(2, weight = int(z*num_columns), uniform='c') self.columnconfigure(3, weight = int(x), uniform='c') self.frame_column_header.grid(row=0, column=2, sticky='nsew') self.frame_table.grid(row=1, column=2, sticky='nsew') self.v_scroll.grid(row=1, column=3, sticky='ns') self.h_scroll.grid(row=2, column=2, sticky='ew') self.button_settings.grid(row=0, column=3, sticky='nsew') self.frame_column_time_header.grid(row=0, column=0, sticky='nsew') self.frame_column_time_header.rowconfigure(0, weight=1, uniform='r') self.frame_column_time_header.columnconfigure(0, weight=1, uniform='c') self.frame_column_index_header.grid(row=0, column=1, sticky='nsew') self.frame_column_index_header.rowconfigure(0, weight=1, uniform='r') self.frame_column_index_header.columnconfigure(0, weight=1, uniform='c') self.frame_column_header.rowconfigure(0, weight=1, uniform='r') self.frame_column_header.columnconfigure(tuple(x for x in range(num_columns)), weight=1, uniform='c') self.frame_table.rowconfigure(0, weight=1, uniform='r') self.frame_table.columnconfigure(tuple(x for x in range(num_columns)), weight=1, uniform='c') self.set_offset_range() self.label_time = ctk.CTkLabel(self.frame_column_time_header, text='Time', fg_color=self.color, font=self.font_header) self.label_time.grid(row=0, column=0, sticky='nsew', padx=2, pady=2) self.label_index = ctk.CTkLabel(self.frame_column_index_header, text='Index', fg_color=self.color, font=self.font_header) self.label_index.grid(row=0, column=0, sticky='nsew', padx=2, pady=2) self.frame_column_time = CTkTableColumn(self, 'Time', self.dataframe['Time'], self.row_offset, num_rows, self.color, self.font_data) self.frame_column_time.grid(row=1, column=0, sticky='nsew') self.frame_column_index = CTkTableColumn(self, 'Index', self.dataframe['Index'], self.row_offset, num_rows,self.color, self.font_data) self.frame_column_index.grid(row=1, column=1, sticky='nsew') for i in range(num_columns): # color = f"#{random.randint(0, 0xFFFFFF):06x}" frame = ctk.CTkFrame(self.frame_column_header, corner_radius=0) frame.grid(row=0, column=i, sticky='nsew') frame.rowconfigure(0, weight=1, uniform='r') frame.columnconfigure(0, weight=1, uniform='c') self.frame_column_header_array.append(ctk.CTkLabel(frame, text=self.selected_cols[i+self.column_offset], fg_color=self.color, font=self.font_header)) self.frame_column_header_array[-1].grid(row=0, column=0, sticky='nsew', padx=2, pady=2) self.table_frame_array.append(CTkTableColumn(self.frame_table, self.selected_cols[i+self.column_offset], self.dataframe[self.selected_cols[i+self.column_offset]], self.row_offset, num_rows, self.color, self.font_data)) self.table_frame_array[-1].grid(row=0, column=i, sticky='nsew') def update_table(self): num_rows = min(len(self.dataframe[self.selected_cols[-1]]), self.view_bounds[0]) num_columns = min(len(self.selected_cols), self.view_bounds[1])-2 for table_column in [self.frame_column_time, self.frame_column_index]: data = self.dataframe[table_column.header] for j in range(num_rows): text = '' if j + self.row_offset < len(data): if table_column.header == 'Index': text = str(int(data[j + self.row_offset])) else: try: text = str(signif(data[j + self.row_offset], 4)) except: text = str(data[j + self.row_offset]) table_column.array_labels[j].configure(text=text.replace(' ', '\n')) for i in range(num_columns): self.frame_column_header_array[i].configure(text = self.selected_cols[i+self.column_offset]) data = self.dataframe[self.selected_cols[i+self.column_offset]] for j in range(num_rows): text = '' if j + self.row_offset < len(data): if self.table_frame_array[i].header == 'Index': text = int(data[j + self.row_offset]) else: try: text = str(signif(data[j + self.row_offset], 4)) except: text = str(data[i + self.row_offset]) self.table_frame_array[i].array_labels[j].configure(text=text.replace(' ', '\n')) def update_view(self, value, dir): row_offset = round(value*self.row_offset_max) column_offset = self.column_offset if dir == 'col': column_offset = round(value*self.column_offset_max) row_offset = self.row_offset if row_offset != self.row_offset or column_offset!= self.column_offset: self.row_offset = row_offset self.column_offset = column_offset self.update_table() def set_offset_range(self): self.row_offset_max = len(self.dataframe[self.selected_cols[0]]) - self.view_bounds[0] self.column_offset_max = len(self.selected_cols) - self.view_bounds[1] + 2 class CTkTableColumn(ctk.CTkFrame): def __init__(self, master, header, data, offset, num_rows, color, font): super().__init__(master, corner_radius=0) self.header = header self.array_frames = [] self.array_labels = [] self.rowconfigure(tuple(x for x in range(num_rows)), weight=1, uniform='r') self.columnconfigure(0, weight=1, uniform='c') for i in range(num_rows): text = '' if i+offset < len(data): if header == 'Index': text = str(int(data[i+offset])) else: try: text = str(signif(data[i+offset], 4)) except: text = str(data[i+offset]) self.array_frames.append(ctk.CTkFrame(master=self, corner_radius=0)) self.array_frames[-1].grid(row=i, column=0, sticky='nsew') self.array_frames[-1].rowconfigure(0, weight=1, uniform='r') self.array_frames[-1].columnconfigure(0, weight=1, uniform='c') self.array_labels.append(ctk.CTkLabel(master=self.array_frames[-1], text=text.replace(' ', '\n'), anchor='center', fg_color=color, font=font)) self.array_labels[-1].grid(row=0, column=0, sticky='nsew', padx=2, pady=2) def signif(arr, p): flag = False if isinstance(arr, np.ndarray): arr = arr.tolist() if not isinstance(arr, list): arr = [arr] flag = True arr_out = [] for x in arr: x_positive = np.where(np.isfinite(x) & (x != 0), np.abs(x), 10**(p-1)) mags = 10 ** (p - 1 - np.floor(np.log10(x_positive))) x = np.round(x * mags) / mags arr_out.append(np.format_float_positional(x, precision=p, unique=False, fractional=False, trim='k')) if flag: return arr_out[0] else: return np.asarray(arr_out) def lcm(a, b): return abs(a * b) // math.gcd(a, b)
效果展示
预期效果

两个表格均设置columnspan=2时的效果

表格1设columnspan=2、表格2设columnspan=1时的效果

内容的提问来源于stack exchange,提问作者Dak
相关产品推荐
相关产品推荐

