如何使用Python tkinter在已有Frame中创建可滚动Frame及滚动条异常排查
解决方案
核心问题
- 同一父容器混用
grid和pack布局管理器导致布局冲突,滚动条无法正常渲染 - 仅给Canvas绑定了尺寸变化事件,内部滚动区域内容变化时没有同步更新滚动范围
- 主Frame的
place()方法未配置参数,没有正确填充窗口
修正后代码
import tkinter as tk from tkinter import ttk class MyGUI(tk.Frame): def __init__(self, parent): tk.Frame.__init__(self, parent) # define variables GRID = 25 X = GRID*20 Y = GRID*15 # create spinbox self.Label = tk.Label(text='Number of Shafts') self.Label.grid(row=0, column=0) self.Spinbox = tk.Spinbox(from_=0, to=10, width=3) self.Spinbox.grid(row=0, column=1) # 新增滚动容器,隔离pack和grid布局 self.scroll_container = tk.Frame(self) self.scroll_container.grid(row=1, column=0, columnspan=2) # create scrollable frame self.Table = tk.Canvas(self.scroll_container, height=100, width=150, background='white', highlightthickness=1, highlightbackground='black') self.Table.pack(side='left', fill='both', expand=True) self.Scrollbar = ttk.Scrollbar(self.scroll_container, orient='vertical', command=self.Table.yview) self.Scrollbar.pack(side='right', fill='y') self.Table.configure(yscrollcommand=self.Scrollbar.set) self.Scrollable_Frame = ttk.Frame(self.Table) self.Table.create_window((0, 0), window=self.Scrollable_Frame, anchor="nw") # 给内部滚动框架绑定尺寸变化事件,内容更新时同步滚动范围 self.Scrollable_Frame.bind("<Configure>", lambda e: self.Table.configure(scrollregion=self.Table.bbox('all'))) for i in range(50): ttk.Label(self.Scrollable_Frame, text=("Sample label %d" % i)).pack() # create canvas self.canvas = tk.Canvas(self, width=X+1, height=Y+1, background='white', highlightthickness=1, highlightbackground='black') self.canvas.grid(row=0, column=2, rowspan=2) # create grid for i in range(0, Y, GRID): self.canvas.create_line(0, i, X, i, fill='gray') for i in range(0, X, GRID): self.canvas.create_line(i, 0, i, Y, fill='gray') # create rectangle x0 = GRID*3 y0 = GRID*4 wid = GRID hei = GRID self.create_shaft(x0, y0, wid, hei) # add bindings to clicks self._drag_data = {"x": 0, "y": 0, "item": None} self.canvas.tag_bind('inertia', "<ButtonPress-1>", self.drag_start) self.canvas.tag_bind('inertia', "<ButtonRelease-1>", self.drag_stop) self.canvas.tag_bind('inertia', "<B1-Motion>", lambda event, grid_x=GRID, grid_y=GRID: self.drag(event, grid_x, grid_y)) def create_shaft(self, x0, y0, wid, hei): """Create shaft drawing""" self.canvas.create_rectangle(x0, y0, x0+wid, y0+hei, fill='gray', tags=('inertia',)) def drag_start(self, event): """Beginning drag of an object""" # record the item and its location self._drag_data["item"] = self.canvas.find_closest(event.x, event.y)[0] self._drag_data["x"] = event.x self._drag_data["y"] = event.y def drag_stop(self, event): """End drag of an object""" # reset the drag information self._drag_data["item"] = None self._drag_data["x"] = 0 self._drag_data["y"] = 0 def drag(self, event, grid_x, grid_y): """Handle dragging of an object""" # compute how much the mouse has moved delta_x = round((event.x - self._drag_data["x"])/grid_x)*grid_x delta_y = round((event.y - self._drag_data["y"])/grid_y)*grid_y # move the object the appropriate amount self.canvas.move(self._drag_data["item"], delta_x, delta_y) # record the new position self._drag_data["x"] += delta_x self._drag_data["y"] += delta_y if __name__ == "__main__": app = tk.Tk() app.title('hi') # 主Frame用pack填充整个窗口 MyGUI(app).pack(fill=tk.BOTH, expand=True) app.mainloop()
内容的提问来源于stack exchange,提问作者kostas1335
相关产品推荐
相关产品推荐

