tkinter 帧与滚动条 - 元素溢出到其他帧
我想做一个用户界面,里面有两个垂直堆叠的框:
frame1
: 输入设置frame2
: 绘图
我需要很多参数,所以需要滚动条。我尝试了不同的类来实现带滚动条的框,但它们似乎都有同样的问题。
问题是,虽然我有一个能用的滚动条,但它并不能隐藏那些在框的可见区域之外的元素。这就导致这些元素溢出到其他框里:
你可以看到,顶部框外的元素还是以某种方式显示出来了,继续出现在第二个框里。
下面是理解这个问题的代码。
有什么建议吗?
import tkinter as tk
from tkinter import ttk
from tkinter.constants import *
class VerticalScrolledFrame(ttk.Frame):
def __init__(self, *args, **kw):
ttk.Frame.__init__(self, *args, **kw)
# Create a canvas object and a vertical scrollbar for scrolling it.
vscrollbar = ttk.Scrollbar(self, orient=VERTICAL)
vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE)
self.canvas = tk.Canvas(self, bd=0, highlightthickness=0, yscrollcommand=vscrollbar.set)
self.canvas.pack(side=LEFT, fill=BOTH, expand=TRUE)
vscrollbar.config(command = self.canvas.yview)
# Reset the view
self.canvas.xview_moveto(0)
self.canvas.yview_moveto(0)
# Create a frame inside the canvas which will be scrolled with it.
self.interior = ttk.Frame(self.canvas)
self.interior.bind('<Configure>', self._configure_interior)
self.canvas.bind('<Configure>', self._configure_canvas)
self.interior_id = self.canvas.create_window(0, 0, window=self.interior, anchor=NW)
def _configure_interior(self, event):
# Update the scrollbars to match the size of the inner frame.
size = (self.interior.winfo_reqwidth(), self.interior.winfo_reqheight())
self.canvas.config(scrollregion=(0, 0, size[0], size[1]))
if self.interior.winfo_reqwidth() != self.canvas.winfo_width():
# Update the canvas's width to fit the inner frame.
self.canvas.config(width = self.interior.winfo_reqwidth())
def _configure_canvas(self, event):
if self.interior.winfo_reqwidth() != self.canvas.winfo_width():
# Update the inner frame's width to fill the canvas.
self.canvas.itemconfigure(self.interior_id, width=self.canvas.winfo_width())
#Create 2 vertically stacked frames and add it to the root
root = tk.Tk()
root.geometry('1280x1024')
root.resizable(width=True,height=True)
topframe = ttk.LabelFrame(root,text='Top', width=1280, height=200)
mainframe = ttk.LabelFrame(root,text='Results', width=1280, height=1024-200)
topframe.grid(row=0,column=0,sticky='news')
mainframe.grid(row=1,column=0,sticky='news')
#Create scrolled frame
frame = VerticalScrolledFrame()
#Add many elements to it, that would require a scrollbar
for i in range(20):
ttk.Label(text=f'Entry {i}').grid(in_=frame.interior,row=i,column=0,sticky='news')
#Resizing the frames
frame.grid(in_=topframe,row=0,column=0,sticky='news')
topframe.columnconfigure(0,weight=1)
topframe.rowconfigure(0,weight=1)
root.mainloop()
我尝试了很多方法,但都没用。一开始我用相对宽度和高度设置了顶部框/主框。而且我程序中的顶部框实际上是一个笔记本,但这并没有解决溢出的问题。
1 个回答
0
问题在于,tkinter使用父子关系来决定控件的叠放顺序(也就是哪些控件会在其他控件的上面)。因为你把标签创建为根窗口的子控件,所以它们在叠放顺序中会比画布里面的框架要高。
最简单的解决办法是把标签放到内框架里面,或者继续使用 in_
,把标签设置为 frame
(也就是 VerticalScrolledFrame
的实例)的子控件。
for i in range(20):
ttk.Label(frame, text=f'Entry{i}').grid(in_=frame.interior,...)
如果想深入了解叠放顺序,可以查看 Tcler's wiki上的叠放顺序。虽然例子都是用tcl写的,但转换成tkinter的语法其实很简单。