Tkinter-使用网格管理器设置高度

时间:2018-10-04 18:14:14

标签: python python-3.x tkinter

我正在尝试使用Tkinter和Python构建简单的GUI应用程序。该应用程序看起来应该差不多

------------------------------
Label-1 | Canvas-1
------------------------------
Label-2 | Canvas-2
------------------------------
Label-3 | Canvas-3
------------------------------
 . . .
Label-3 | Canvas-3
------------------------------
        | scrollbar-horizontal
------------------------------

,其中滚动条应同时在所有Canvas对象上滚动。我能够完成那部分,但是当我尝试为每一行设置高度时,我都遇到了问题。基本上我希望第一行在另一行下并具有预定义的高度。我决定使用网格管理器来实现这一目标。

下面是一个最小的示例:

import tkinter
import tkinter.font


class LineData(object):

    def __init__(self, desc, box):
        self.desc = desc
        self.box = box

class LinePlotter(object):

    def __init__(self, label, canvas, desc, box):
        self.label = label
        self.canvas = canvas
        self.desc = desc
        self.box = box

    def plot(self):
        self.label.set(self.desc)
        x1, y1 = self.box[0], 1
        x2, y2 = self.box[1], 20
        print(self.desc)
        print(x1, y1, x2, y2)
        print(x2+100, y1, x2+(x2-x1)+100, y2)
        self.canvas.create_rectangle(x1, y1, x2, y2, outline="#D1D0CE", 
                                     width=4, fill="#D1D0CE")

        self.canvas.create_rectangle(x2+100, y1, x2+(x2-x1)+100, y2, outline="#D1D0CE",
                                     width=4, fill="#D1D0CE")


class Plotter(tkinter.Frame):

    def __init__(self, parent, lines_data):
        super().__init__(parent)
        self.parent = parent
        self.lines_data = lines_data

    def set_scroll_bar(self):
        x1, y1, x2, y2 = self.canvases[0].bbox(tkinter.ALL)
        x1 = y1 = 0
        for c in self.canvases:
            t1, u1, t2, u2 = c.bbox(tkinter.ALL)
            x1 = min(x1, t1)
            x2 = max(x2, t2)
            y1 = min(y1, u1)
            y2 = max(y2, u2)

        print("final=", x1, y1, x2, y2)
        for c in self.canvases:
            c.config(scrollregion=(x1-5, y1-5, x2+5, y2+5))

    def xview(self, *args):
        for c in self.canvases:
            c.xview(*args)

    def initUI(self):

        self.scrollX = tkinter.Scrollbar(self, orient=tkinter.HORIZONTAL)

        self.scrollX['command'] = self.xview
        self.scrollX.grid(row=2, column=1, sticky='NSEW')

        self.canvases = []

        h = 10
        for row_idx, line_data in enumerate(self.lines_data):
            desc = tkinter.StringVar()
            font = tkinter.font.Font(size=11)
            label = tkinter.Label(self, textvariable=desc, font=font, 
                                  height=h)
            label.grid(row=row_idx, column=0, sticky=tkinter.W)

            canvas = tkinter.Canvas(self, bg='white', 
                                    xscrollcommand=self.scrollX.set, 
                                    height=h)

            line = LinePlotter(desc, canvas, line_data.desc, line_data.box)
            line.plot()

            canvas.grid(row=row_idx, column=1, sticky=tkinter.W)
            self.canvases.append(canvas)

        self.set_scroll_bar()

        self.pack(expand=True, fill=tkinter.X)


l1 = LineData("L1", (50, 60))
l2 = LineData("L2", (200, 250))

root = tkinter.Tk()

Plotter(root, [l1, l2]).initUI()
root.mainloop()  

当我在h = None中设置initUI时,我看到对象正在扩展到整个窗口

enter image description here

当我设置h = 10时,我看到行变得越来越细,但它们一直分布在屏幕上。

enter image description here

当我设置h = 50时,我仅看到第一行。

enter image description here

理想情况下,我希望看到与h = 10类似的东西,但另一行下面。我该如何实现?

1 个答案:

答案 0 :(得分:1)

您的问题是创建画布时h表示像素,但是配置标签时的行数。将它用于一个或另一个,但不能同时使用。

假设您希望画布的高度为10像素,只需从标签上除去高度即可。这将使标签尽可能小。它仍然会高于10像素,但是您可以通过选择较小的字体来解决此问题。

当我简单地从标签中删除height=h时,我得到的结果是:

enter image description here