Tkinter网格布局异常:列宽与行高配置未生效问题求助
问题分析与修复方案
核心问题点
- 混合使用布局管理器:主框架
frame同时调用pack()和grid(),Tkinter不允许同一组件混用两种布局规则,直接导致布局逻辑冲突。 - 第一行文本框拆分错误:需求是一个占5列的右侧文本框,但代码拆成两个组件(占2列+3列),增加布局复杂度且易引发列宽分配异常。
- 图片固定宽度限制缩放:图片标签设置
width=new_width强制固定宽度,忽略了列权重配置,导致对应列无法随窗口缩放。 - 行权重设置不符合需求:第一行权重设为1会随窗口拉伸,但需求是行高适配图片最小高度,应设为0并指定最小高度。
- 文本框固定高度:第一行文本框的
height=7参数固定了高度,无法自适应图片高度。
修复后的完整代码
import tkinter as tk from ctypes import windll import sys from PIL import Image, ImageTk windll.shcore.SetProcessDpiAwareness(1) quitapp = False maxscreens = 1 lookups = ['AVG', 'BTC', 'ETH', 'USDT'] domesticdict = {} def show_data(data): def search_text(event=None): # Clear previous highlights text_widget.tag_remove("highlight", "1.0", tk.END) # Get the search query search_query = search_entry.get().upper() if search_query: start_pos = "1.0" instance_count = 0 first_instance_pos = None while True: start_pos = text_widget.search(search_query, start_pos, stopindex=tk.END) if not start_pos: break if not first_instance_pos: first_instance_pos = start_pos instance_count += 1 end_pos = f"{start_pos}+{len(search_query)}c" text_widget.tag_add("highlight", start_pos, end_pos) start_pos = end_pos text_widget.tag_config("highlight", background="yellow", foreground="black") if first_instance_pos: text_widget.see(first_instance_pos) result_label.config(text=f"Found {instance_count} instances.") data_window = tk.Toplevel() data_window.title("Domestic Sources for Binance Tokens") # search entry button search_entry = tk.Entry(data_window) search_entry.pack(side=tk.TOP, padx=5, fill=tk.X) search_button = tk.Button(data_window, text="Search", command=search_text) search_button.pack(side=tk.TOP, padx=5) result_label = tk.Label(data_window, text="") result_label.pack(side=tk.TOP, padx=5) data_window.bind("<Return>", search_text) # Bind the search_text function to the Enter key # Create a frame to hold the Text and Scrollbar widgets frame = tk.Frame(data_window) frame.pack(expand=True, fill=tk.BOTH, padx=5, pady=5) # Create the Text widget text_widget = tk.Text(frame, wrap=tk.WORD, background='black', foreground='white') text_widget.pack(side=tk.LEFT, expand=True, fill=tk.BOTH) # Create the Scrollbar widget scrollbar = tk.Scrollbar(frame) scrollbar.pack(side=tk.RIGHT, fill=tk.Y) # Link the Scrollbar to the Text widget text_widget.config(yscrollcommand=scrollbar.set) scrollbar.config(command=text_widget.yview) for key, value in data.items(): text_widget.insert(tk.END, f"{key}: {value}\n") data_window.mainloop() def on_image_click(event, data): show_data(data) def create_tkinter_window(): global domesticdict # Create the main window root = tk.Tk() root.title("Crypto Monitor") root.state('zoomed') fontname = 'Courier' fontsize = 14 frame = tk.Frame(root, background='black') frame.pack(expand=True, fill=tk.BOTH) # Create the text boxes - 合并第一行右侧的两个文本框为一个 text_box_topleft = tk.Text(frame, font=(fontname, fontsize), wrap=tk.WORD, foreground="white", background='black', bd=20, highlightthickness=0) text_box_topright = tk.Text(frame, font=(fontname, fontsize), wrap=tk.WORD, foreground="white", background='black', bd=20, highlightthickness=0) text_box_left = tk.Text(frame, font=(fontname, fontsize), wrap=tk.WORD, foreground="white", background='black', bd=20, highlightthickness=0) text_box_right = tk.Text(frame, font=(fontname, fontsize), wrap=tk.WORD, foreground="white", background='black', bd=20, highlightthickness=0) # load the logo image_file = "Crypto Monitor.png" image = Image.open(image_file) new_width = 500 aspect_ratio = float(image.height) / float(image.width) new_height = int(new_width * aspect_ratio) image = image.resize((new_width, new_height), Image.LANCZOS) photo = ImageTk.PhotoImage(image) # 去掉固定width,让grid控制宽度 image_label = tk.Label(frame, image=photo, background='black') image_label.image = photo # 保留引用防止图片被回收 image_label.bind("<Button-1>", lambda event: on_image_click(event, domesticdict)) # Position the text boxes using the grid geometry manager text_box_topleft.grid(row=0, column=0, columnspan=5, padx=0, pady=0, sticky="nsew") image_label.grid(row=0, column=5, columnspan=2, padx=0, pady=0, sticky="nsew") text_box_topright.grid(row=0, column=7, columnspan=5, padx=0, pady=0, sticky="nsew") # 改为占5列 text_box_left.grid(row=1, column=0, columnspan=6, padx=0, pady=0, sticky="nsew") text_box_right.grid(row=1, column=6, columnspan=6, padx=0, pady=0, sticky="nsew") # Configure the grid to resize with the window # 第一行权重设为0,最小高度设为图片高度,确保行高适配图片 frame.grid_rowconfigure(0, weight=0, minsize=new_height) frame.grid_rowconfigure(1, weight=1) # 第二行占剩余空间 for i in range(12): frame.grid_columnconfigure(i, weight=1) # 12列等宽,随窗口缩放 def on_close(): global quitapp quitapp = True root.destroy() sys.exit() root.protocol("WM_DELETE_WINDOW", on_close) try: root.mainloop() except KeyboardInterrupt: pass create_tkinter_window()
关键修改说明
- 移除混合布局调用:删除
frame.grid(),仅保留frame.pack(expand=True, fill=tk.BOTH),确保布局管理器唯一。 - 合并第一行右侧文本框:将拆分的两个文本框合并为一个,设置
columnspan=5,匹配需求的布局结构。 - 取消图片固定宽度:删除
image_label的width=new_width参数,让grid的sticky="nsew"和列权重控制图片宽度,实现随窗口缩放。 - 调整行权重与最小高度:第一行设置
weight=0和minsize=new_height,保证行高刚好适配图片;第二行设weight=1,占据窗口剩余垂直空间。 - 移除文本框固定高度:删除第一行文本框的
height=7参数,让高度随行高自适应图片尺寸。
内容的提问来源于stack exchange,提问作者Muhammad Daud
相关产品推荐
相关产品推荐

