【问题标题】:Specific issue using pack while creating a layout创建布局时使用包的特定问题
【发布时间】:2017-03-11 10:21:03
【问题描述】:

我必须使用 tkinter 库来创建 GUI。

我有这个代码:

# -*- coding: UTF-8 -*-
import tkinter as tk

class Application(tk.Frame):

    resx=1600
    resy=900

    def __init__(self, master=None):
        tk.Frame.__init__(self, master)
        self.pack(fill="both", expand=1)
        self.createWidgets()
        master.minsize(self.resx, self.resy)
        master.maxsize(self.resx, self.resy)

    def createWidgets(self):
        self.hi_there = tk.Button(self)
        self.hi_there["text"] = "Create new window"
        self.hi_there["command"] = self.PlayMode
        self.hi_there.pack(side="top")

    def ShowMenu(self, master):
        print("Here I need DELETE master, in my case PlayM")

    def PlayMode(self):
        PlayM = tk.Tk()
        PlayM.minsize(self.resx, self.resy)
        PlayM.maxsize(self.resx, self.resy)
        PlayM.title("Game")

        bf= tk.Frame(PlayM, bg="blue")
        bf.pack(side="bottom", fill=tk.X, expand = 1)
        lbTEST=tk.Label(bf)
        lbTEST["text"] = "TESTING"
        lbTEST.pack()

        mf = tk.Frame(PlayM,bg="red")
        mf.pack(side="right", fill=tk.Y, expand=1)
        self.LogOut = tk.Button(mf)
        self.LogOut["text"] = "LOGOUT"
        self.LogOut.pack()
        self.LogOut["command"] = self.ShowMenu(PlayM)

root = tk.Tk()
app = Application(master=root)
app.master.title("Useless think")
app.mainloop()

我需要这样的图片:

我不知道为什么我的代码不起作用。当我打包我的bf(底部框架)并设置side = "bottom",但它出现在屏幕中间。为什么? 当我打包 mf(菜单框架)时,与 side = "right" 相同

我还有一个问题。关于注销按钮。我设置了命令的方法"ShowMenu"

当我运行我的代码时,这个方法只会自动启动一次,但是当我点击按钮时没有任何反应。为什么?

【问题讨论】:

    标签: python button tkinter frame pack


    【解决方案1】:

    首先,您的代码存在严重缺陷。您不应创建多个Tk 实例。如果您需要创建其他窗口,请创建 Toplevel 的实例。

    当我打包我的 bf(底部框架)并设置 side =“底部”时,它出现在屏幕中间。为什么?

    对于mfmf,您将expand 设置为1,因此每个最终都会占用窗口中可用空间的一半。如果您只是将expand 设置为 0(零)或将False 设置为bf,它只会占用必要的空间。

    bf.pack(side="bottom", fill=tk.X, expand = 0)
    

    作为一般规则,您应该只在单个小部件(“英雄”小部件)上为 expand 设置真值,除非您希望在小部件之间平均分配额外空间。

    当我运行我的代码时,这个方法只会自动启动一次,但是当我点击按钮时没有任何反应。为什么?

    因为你告诉它运行。看看这段代码:

    self.LogOut["command"] = self.ShowMenu(PlayM)
    

    和这段代码一模一样:

    result = self.ShowMenu(PlayM)
    self.logOut["command"] = result
    

    看到问题了吗?

    command 属性需要一个函数的引用。粗略翻译,这意味着你不能使用()。如果您需要将参数传递给命令,典型的解决方案是使用 functools.partiallambda 创建对匿名函数的引用,该函数将使用参数调用真实函数:

    self.logOut["command"] = lambda arg=PlayM: self.ShowMenu(arg)
    

    【讨论】:

    • 一如既往,Bryan 的回答比我好 ;-)
    • 特别感谢 Bryan 和所有其他人 ;) 我的问题的所有答案都非常有用。我想再问一个问题。有人在“现实生活”中使用 tkinter 库吗?还是只是“大学”语言?(仅供学生玩耍)。我之所以问,是因为有时我很难找到可靠的文档。
    • @DoctorCZE 我想说,从我的角度来看,tkinter 对于学习创建 GUI(通常)和快速制作简单 UI 的原型很有用,也许对于个人项目。我不认为现在公司使用 tkinter,因为有现代(“更好”)的替代品,例如 Kivy,而且现在 UI 往往被推送到浏览器。
    • @DoctorCZE 我可以分享这对于快速制作原型非常有用。但与 nbros 的看法相反,它仍然用于商业应用。没有广泛使用,但仍在使用。对于可靠的文档,请使用 TCL 文档。
    • @DoctorCZE:我在现实生活中使用它来创建专业环境中使用的 GUI。
    【解决方案2】:

    您使用 pack 方法而不是 grid 有什么具体原因吗?

    您可以像这样配置您的应用程序框架:

    self.grid_rowconfigure(0, weight=1)    #make the first "upper" row expand
    self.grid_rowconfigure(1, weight=0)    #leave the second "lower" row and do not expand it
    
    self.grid_columnconfigure(0, weight=0) # first column, do not expand
    self.grid_columnconfigure(1, weight=1) # second columnd, DO expand
    self.grid_columnconfigure(0, weight=0) # third column, do not expand
    

    在您的大型机/应用程序类上,然后调用:

    bf.grid(row=1, column=0, columnspan=3, sticky=tk.NW+tk.SE) # span over three columns
    lf.grid(row=0, column=0, sticky=tk.NW+tk.SE) # default is to span over one column
    rf.grid(row=0, column=2, sticky=tk.NW+tk.SE)
    

    编辑

    非常抱歉,我忘了提注销按钮。 您在绑定时调用事件处理程序,因此它将在那里执行。

    如果您想让它传递值,请使用:

    • command=lambda parent=PlayM: self.ShowMenu(parent)
    • 使用类对象在创建时存储您的父引用 self._Parent = PlayM 并在 ShowMenu 中使用它

    我个人更喜欢为单个值存储对象。如果你有很多窗户要销毁,我会使用 lambda。

    【讨论】:

      【解决方案3】:

      除了Bryan Oakley 已经提到的问题和R4PH43L 使用grid 给出的解决方案之外,这里有一个可能的解决方案,仅使用pack

      这个想法是,通过使用side="left"(或side="right"),然后使用side="top"(或side="bottom")不会像您期望的那样工作。 在一个框架内,您应该只使用 side 的值(在同一框架中打包小部件时),它们可以是垂直的("top""bottom")或水平的("right""left"),但不是两者。因此,要仅使用 pack 完成像您这样的布局,您需要额外的框架!

      # -*- coding: UTF-8 -*-
      import tkinter as tk
      
      class Application(tk.Frame):
      
          resx=400
          resy=200
      
          def __init__(self, master=None):
              tk.Frame.__init__(self, master, bg="red")
              self.pack(fill="both", expand=1)
              self.create_widgets()
              master.geometry("400x200+100+500")
      
          def create_widgets(self):
              self.hi_there = tk.Button(self)
              self.hi_there["text"] = "Create new window"
              self.hi_there["command"] = self.play_mode
              self.hi_there.pack(side="top")
      
          def show_menu(self, master):
              print("Here I need DELETE master, in my case play_m")
      
          def play_mode(self):
              # Using a Toplevel instead of a Tk
              # You should have just one Tk in your app
              play_m = tk.Toplevel()
              play_m.geometry("400x200+100+500")
              play_m.title("Game")
      
              top_frame = tk.Frame(play_m, bg="blue")       
              top_frame.pack(side="top", fill="both", expand=True)
      
              left_top_frame = tk.Frame(top_frame, bg="white")
              left_top_frame_label = tk.Label(left_top_frame, text="left top frame")
              left_top_frame_label.pack()
              left_top_frame.pack(side="left", fill="y")
      
              middle_top_frame = tk.Frame(top_frame, bg="black")
      
              middle_top_frame_button = tk.Button(middle_top_frame, text="Logout", command=play_m.destroy)
              middle_top_frame_button.pack()
              middle_top_frame.pack(side="left", fill="both", expand=True)
      
              right_top_frame = tk.Frame(top_frame, bg="white")
              right_top_frame_label = tk.Label(right_top_frame, text="right top frame")
              right_top_frame_label.pack()
              right_top_frame.pack(side="right", fill="y")
      
              bottom_frame = tk.Frame(play_m, bg="yellow")
              bottom_frame_label = tk.Label(bottom_frame, text="bottom frame")
              bottom_frame_label.pack()        
              bottom_frame.pack(side="top", fill="both")
      
      
      root = tk.Tk()
      app = Application(master=root)
      app.master.title("Useless think")
      app.mainloop()
      

      这是 OS X (Sierra) 上 Tk 主窗口的结果:

      二级顶层

      为了展示,我稍微改变了尺寸。我还将方法重命名为使用_ 和小写字母。

      【讨论】:

        猜你喜欢
        • 2014-12-22
        • 2014-12-21
        • 2021-08-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-23
        相关资源
        最近更新 更多