Python 2.7 / Tkinter多帧和菜单

时间:2017-09-11 18:00:09

标签: python tkinter frames

我想创建一个管理工具,左边是菜单,右边是框架。我读了一篇关于更改框架的教程,并尝试从那里开始。问题是右框架应始终为1200x750 ..而这不起作用。我知道python,但仍然有一些学习上面向对象的python ... 有人看到我在这里缺少什么吗?

import Tkinter as tk
import tkFont as tkfont

class SampleApp(tk.Tk):

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        self.title_font = tkfont.Font(family='Helvetica', size=18, weight="bold", slant="italic")

        self.grid_columnconfigure(1, weight=0)
        self.grid_columnconfigure(2, weight=1)
        self.grid_rowconfigure(1, weight=1)

        leftframe = tk.Frame(self, width=300, height=750, bd=1, relief = tk.SOLID, bg="white")
        rightframe = tk.Frame(self, width=1200, height=750, bd=1, relief = tk.SOLID, bg="white")
        bottomframe = tk.Frame(self, width=1500, height=50, bd=1, relief = tk.SOLID, bg="white")

        leftframe.grid(row=1,column=1, sticky="nsew")
        rightframe.grid(row=1, column=2, sticky="nsew")
        bottomframe.grid(row=2, column=1, columnspan=2, sticky="nsew")

        leftframe.pack_propagate(0) # <-- still got this in to make the menu width fixed

        button1 = tk.Button(leftframe, text="Start page" , anchor="w", bg="white", bd=0, command=lambda: self.show_frame("StartPage")).pack(padx=10, anchor="sw", fill="x")
        button2 = tk.Button(leftframe, text="Page 1"     , anchor="w", bg="white", bd=0, command=lambda: self.show_frame("PageOne")).pack(padx=10, fill="x")
        button3 = tk.Button(leftframe, text="Page 2"     , anchor="w", bg="white", bd=0, command=lambda: self.show_frame("PageTwo")).pack(padx=10, fill="x")
        button4 = tk.Button(leftframe, text="Page 3"     , anchor="w", bg="white", bd=0, command=lambda: self.show_frame("PageOne")).pack(padx=10, fill="x")
        button5 = tk.Button(leftframe, text="Page 4"     , anchor="w", bg="white", bd=0, command=lambda: self.show_frame("PageOne")).pack(padx=10, fill="x")
        button5 = tk.Button(leftframe, text="Page 5"     , anchor="w", bg="white", bd=0, command=lambda: self.show_frame("PageOne")).pack(padx=10, fill="x")

        self.frames = {}
        for F in (StartPage, PageOne, PageTwo):
            page_name = F.__name__
            frame = F(parent=rightframe, controller=self)
            self.frames[page_name] = frame

            # put all of the pages in the same location;
            # the one on the top of the stacking order
            # will be the one that is visible.
            frame.config(bg="white")
            frame.grid(row=0, column=0, sticky="news")


        self.show_frame("StartPage")
        self.init_topmenu()

    def show_frame(self, page_name):
        '''Show a frame for the given page name'''
        frame = self.frames[page_name]
        frame.tkraise()


    def init_topmenu(self):
        menubar = tk.Menu(self)
        self.config(menu=menubar)
        fileMenu = tk.Menu(menubar)
        fileMenu.add_command(label="Page 1", command=lambda: self.show_frame("PageOne"))
        fileMenu.add_command(label="Page 2", command=lambda: self.show_frame("PageTwo"))
        menubar.add_cascade(label="File", menu=fileMenu)

class StartPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text="This is the Startpage", font=controller.title_font)
        label.pack(side="top", fill="x", pady=10)

class PageOne(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text="This is page 1", font=controller.title_font)
        label.pack(side="top", fill="x", pady=10)

class PageTwo(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text="This is page 2", font=controller.title_font)
        label.pack(side="top", fill="x", pady=10)


if __name__ == "__main__":
    app = SampleApp()
    window_width = 1500
    window_height = 800
    width = app.winfo_screenwidth()
    height = app.winfo_screenheight()
    app.geometry('%dx%d+%d+%d' % (window_width, window_height, width*0.5-(window_width/2), height*0.5-(window_height/2)))
    app.mainloop()

1 个答案:

答案 0 :(得分:0)

概述

你犯了三个常见的错误:

  1. 您没有要求小部件填充给他们的空间
  2. 你没有告诉tkinter如何分配额外的空间
  3. 您正在关闭几何体传播
  4. 使小部件填充其分配的空间

    调用sticky时,可以使用grid属性解决第一个问题。例如:

    leftframe.grid(row=1,column=1, sticky="nsew")
    rightframe.grid(row=1, column=2, sticky="nsew")
    bottomframe.grid(row=2, column=1, columnspan=2, sticky="nsew")
    

    您还需要对每个页面执行此操作:

    frame.grid(row=0, column=0, sticky="nesw")
    

    分配未使用的空间

    第二个问题可以通过给行和列赋予权重来解决。 Tkinter将使用行或列的weight来确定是否应该为该行或列分配任何剩余空间。这可能是人们在使用grid时最常犯的错误。

    根据经验,只要您使用grid,主窗口小部件应至少有一行和一列非零权重。

    self.grid_columnconfigure(1, weight=0)
    self.grid_columnconfigure(2, weight=1)
    self.grid_rowconfigure(1, weight=1)
    

    不要关闭几何体传播

    您正在关闭几何体传播,这很少是一个好的解决方案。我强烈建议您删除对grid_propagatepack_propagate的所有来电。使用tkinter的最佳方法是配置内部窗口小部件,并让包含的窗口小部件增大或缩小以适应。当您正确设置GUI时,无论当时有什么分辨率或字体处于活动状态,它都将是正确的大小。

    我使用tk或tkinter超过20年,并且需要在这些年中关闭几何传播不超过非常非常少的时间。这是一个有点高级的选项,它只对某些特定的边缘情况有用。

    整理您的代码

    这不会导致问题,但它有助于使您的代码更容易理解。我强烈建议您将窗口小部件的创建与在屏幕上组织它们分开。当您阅读“小部件,网格,小部件,网格,小部件,网格”时,很难对您正在构建的内容进行心理描绘。相反,如果你有“小部件,小部件,小部件”,然后是“网格,网格,网格”,你就会清楚地知道你正在构建什么。

    例如,我会重新安排代码的开头,如下所示:

    self.grid_columnconfigure(1, weight=0)
    self.grid_columnconfigure(2, weight=1)
    self.grid_rowconfigure(1, weight=1)
    
    leftframe = tk.Frame(self, width=300, height=750, bd=1, relief = tk.SOLID, bg="white")
    rightframe = tk.Frame(self, width=1200, height=750, bd=1, relief = tk.SOLID, bg="white")
    bottomframe = tk.Frame(self, width=1500, height=50, bd=1, relief = tk.SOLID, bg="white")
    
    leftframe.grid(row=1,column=1, sticky="nsew")
    rightframe.grid(row=1, column=2, sticky="nsew")
    bottomframe.grid(row=2, column=1, columnspan=2, sticky="nsew")
    

    请注意我在创建leftframerightframebottomframe时如何明确设置父级。没有理由不这样做,它使代码更加自我记录。