为了账号安全,请及时绑定邮箱和手机立即绑定

在Tkinter中向一组小部件添加滚动条

在Tkinter中向一组小部件添加滚动条

慕后森 2019-06-01 13:44:26
我使用Python解析日志文件中的条目,并使用Tkinter显示条目内容,到目前为止,它非常出色。输出是标签小部件的网格,但有时显示的行数比屏幕上的要多。我想添加一个滚动条,看起来应该很简单,但是我想不出来。文档意味着只有列表、文本框、画布和条目小部件支持滚动条接口。所有这些似乎都不适合显示小部件网格。在画布小部件中放置任意的小部件是可能的,但是您似乎必须使用绝对的协调,这样我就不能使用网格布局管理器了?我尝试过将小部件网格放到一个框架中,但这似乎不支持滚动条接口,所以这是行不通的:mainframe = Frame(root, yscrollcommand=scrollbar.set)有人能提出解决这个限制的办法吗?我讨厌用PyQt重写,并将我的可执行映像大小增加这么多,只是为了添加一个滚动条!在Tkinter中向一组小部件添加滚动条
查看完整描述

2 回答

?
慕斯王

TA贡献1864条经验 获得超2个赞

概述

您只能将滚动条与一些小部件关联起来,根小部件和Frame不是那组小部件的一部分。

最常见的解决方案是创建一个画布小部件,并将滚动条与该小部件关联起来。然后,将包含标签小部件的框架嵌入到画布中。确定框架的宽度/高度,并将其输入画布。scrollregion选项,以便滚动区域与框架的大小完全匹配。

在画布上直接绘制文本项并不困难,因此如果画布框架内嵌解决方案看起来过于复杂,您可能需要重新考虑这种方法。由于要创建网格,每个文本项的坐标将非常容易计算,特别是如果每一行的高度相同(如果使用单一字体,可能就是这样)。

要在画布上直接绘图,只需计算出所使用字体的线条高度(这方面有一些命令)。然后,每个y坐标是row*(lineheight+spacing)..x坐标将是基于每列中最宽项的固定数。如果为列中的所有项都赋予标记,则可以使用单个命令调整列中所有项的x坐标和宽度。

面向对象的解决方案

下面是一个使用面向对象方法的画布框架内嵌解决方案的示例:

import tkinter as tkclass 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 tkdef 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()

注:若要在python2.x中执行此操作,请使用Tkinter而不是tkinter在导入语句中


查看完整回答
反对 回复 2019-06-01
  • 2 回答
  • 0 关注
  • 3041 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信