Python 2.7/Tkinter多个框架和菜单 [英] Python 2.7 / Tkinter multiple frames and menu

查看:106
本文介绍了Python 2.7/Tkinter多个框架和菜单的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想制作一个管理工具,其左侧为菜单,右侧为更改框架.我读了一篇有关更改框架的教程,并尝试从那里开始.问题是右框架应始终为1200x750.这是行不通的.我知道python,但仍需要学习一些面向对象的python ... 有人看到我在这里想念的吗?

I want to make a admin tool with a menu to the left and changing frames to the right. I read that one tutorial about changing frames and tried to start from there. The issue is that the rightframe should always be 1200x750.. And that does not work. I know python but still got some learning to do on object oriented python... Does anybody see what i am missing here?

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()

推荐答案

概述

您犯了三个常见错误:

Overview

You are making three common mistakes:

  1. 您不要求窗口小部件填充为其分配的空间
  2. 您没有告诉tkinter如何分配额外的空间
  3. 您要关闭几何传播

使小部件填充其分配的空间

第一个问题可以通过调用grid时使用sticky属性来解决.例如:

Making widgets fill their allocated space

The first problem can be solved by using the sticky attribute when calling grid. For example:

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")

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

You also need to do this with each page:

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

分配未使用的空间

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

Allocating unused space

The second problem can be solved by giving rows and columns a weight. Tkinter will use the weight of a row or column to determine if that row or column should be allocated any leftover space. This is perhaps the most common mistake people make when using grid.

根据经验,每次使用grid时,主窗口小部件至少应具有一行和一列,且权重非零.

As a rule of thumb, any time you use grid, the master widget should have at least one row and one column with a non-zero weight.

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

不要关闭几何传播

您要关闭几何图形传播,这很少是一个好的解决方案.我强烈建议您删除所有对grid_propagatepack_propagate的呼叫.使用tkinter的最佳方法是配置内部窗口小部件,并让包含的窗口小部件增大或缩小以适应.正确设置GUI时,无论当时使用哪种分辨率或字体,它的大小都是正确的.

Don't turn off geometry propagation

You are turning off geometry propagation, which is rarely a good solution. I strongly encourage you to remove all calls to grid_propagate and pack_propagate. The best way to use tkinter is to configure the inner widgets, and let the containing widgets grow or shrink to accomodate. When you set up your GUI properly it will be exactly the right size no matter what resolution or fonts are active at the time.

我使用tk或tkinter已有20多年了,在这些年中,关闭几何图形传播的次数最多,非常少.这是一个有点高级的选项,实际上仅对某些特定的边缘情况有用.

I've used tk or tkinter for over 20 years, and have needed to turn off geometry propagation no more than a very, very few times in all those years. It's a somewhat advanced option that's really only useful for some specific edge cases.

这不是问题的根源,但有助于使代码更易于理解.我强烈建议您将窗口小部件的创建与在屏幕上的组织分开.当您阅读"widget,grid,widget,grid,widget,grid"时,很难对正在构建的内容做出心理印象.相反,如果您有"widget,widget,widget",然后是"grid,grid,grid",则将完全清楚您要构建的内容.

This isn't contributing to the problem, but it contributes to making your code easier to understand. I strongly encourage you to separate the creation of widgets from organizing them on the screen. When you read "widget, grid, widget, grid, widget, grid", it's hard to make a mental image of what you're building. Instead, if you have "widget, widget, widget" followed by "grid, grid, grid" it becomes completely clear what you're building.

例如,我将重新排列代码的开头,使其看起来像这样:

For example, I would rearrange the start of your code to look like this:

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时我也如何显式设置父对象.没有理由不这样做,这使代码更具自记录性.

Notice how I also explicitly set the parent when creating leftframe, rightframe and bottomframe. There's no reason not to, and it makes the code more self-documenting.

这篇关于Python 2.7/Tkinter多个框架和菜单的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆