Python-向Tkinter中的一组小部件添加滚动条
我使用Python来解析日志文件中的条目,并使用Tkinter显示条目内容,到目前为止这是非常棒的。输出是一个标签小部件的网格,但有时有更多的行无法显示在屏幕上。我想添加一个滚动条,看起来应该很简单,但我想不通。 文档意味着只有列表、文本框、画布和条目小部件支持滚动条界面。这些似乎都不适合显示小部件网格。可以在画布小部件中放置任意小部件,但你似乎必须使用绝对坐标,因此我将无法使用网格布局管理器? 我试过将小部件网格放入一个框架中,但它似乎不支持滚动条界面,因此这不起作用:
mainframe = Frame(root, yscrollcommand=scrollbar.set)
有人能建议一个办法绕过这个限制吗?我不想在PyQt中重写,把我的可执行图像大小增加这么多,仅仅是为了添加一个滚动条!
回答:
你只能将滚动条与几个小部件相关联,而根小部件和框架不属于该组小部件。
最常见的解决方案是创建画布小部件并将滚动条与该小部件关联。然后,在画布中嵌入包含标签小部件的框架。确定帧的宽度/高度并将其馈送到canvas scrollregion
选项中,以便scrollregion
与帧的大小完全匹配。
为什么要将小部件放在框架中而不是直接放在画布中?附加到画布的滚动条只能滚动使用创建方法之一创建的项。不能将添加到画布中的项目滚动到“打包”、“放置”或“网格”。通过使用框架,可以在框架内使用这些方法,然后为框架调用一次create_window
。
直接在画布上绘制文本项不是很困难,因此如果frame-embedded-in-a-canvas
解决方案看起来太复杂,你可能需要重新考虑这种方法。由于你正在创建一个网格,因此每个文本项的坐标将非常容易计算,特别是如果每行的高度相同(如果你使用的是单个字体,则可能是相同的高度)。
对于直接在画布上绘制,只需计算出所使用字体的行高(并且有相应的命令)。然后,每个y坐标是row*(lineheight+spacing)
。x
坐标将是基于每列中最宽项的固定数字。如果为列中的所有项提供标记,则可以使用一个命令调整列中所有项的x坐标和宽度。
下面是一个使用面向对象方法嵌入到画布解决方案中的框架示例:
import tkinter as tk # python 3# import Tkinter as tk # python 2
class Example(tk.Frame):
def __init__(self, root):
tk.Frame.__init__(self, root)
self.canvas = tk.Canvas(root, borderwidth=0, background="#ffffff")
self.frame = tk.Frame(self.canvas, background="#ffffff")
self.vsb = tk.Scrollbar(root, orient="vertical", command=self.canvas.yview)
self.canvas.configure(yscrollcommand=self.vsb.set)
self.vsb.pack(side="right", fill="y")
self.canvas.pack(side="left", fill="both", expand=True)
self.canvas.create_window((4,4), window=self.frame, anchor="nw",
tags="self.frame")
self.frame.bind("<Configure>", self.onFrameConfigure)
self.populate()
def populate(self):
'''Put in some fake data'''
for row in range(100):
tk.Label(self.frame, text="%s" % row, width=3, borderwidth="1",
relief="solid").grid(row=row, column=0)
t="this is the second column for row %s" %row
tk.Label(self.frame, text=t).grid(row=row, column=1)
def onFrameConfigure(self, event):
'''Reset the scroll region to encompass the inner frame'''
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
if __name__ == "__main__":
root=tk.Tk()
Example(root).pack(side="top", fill="both", expand=True)
root.mainloop()
程序解决方案
这是不使用类的解决方案:
import tkinter as tk # python 3# import Tkinter as tk # python 2
def populate(frame):
'''Put in some fake data'''
for row in range(100):
tk.Label(frame, text="%s" % row, width=3, borderwidth="1",
relief="solid").grid(row=row, column=0)
t="this is the second column for row %s" %row
tk.Label(frame, text=t).grid(row=row, column=1)
def onFrameConfigure(canvas):
'''Reset the scroll region to encompass the inner frame'''
canvas.configure(scrollregion=canvas.bbox("all"))
root = tk.Tk()
canvas = tk.Canvas(root, borderwidth=0, background="#ffffff")
frame = tk.Frame(canvas, background="#ffffff")
vsb = tk.Scrollbar(root, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand=vsb.set)
vsb.pack(side="right", fill="y")
canvas.pack(side="left", fill="both", expand=True)
canvas.create_window((4,4), window=frame, anchor="nw")
frame.bind("<Configure>", lambda event, canvas=canvas: onFrameConfigure(canvas))
populate(frame)
root.mainloop()
以上是 Python-向Tkinter中的一组小部件添加滚动条 的全部内容, 来源链接: utcz.com/qa/435213.html