Search code examples
pythonbuttontkinterframepack

Specific issue using pack while creating a layout


I must use tkinter library to create GUI.

I have this code:

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

I need something like this picture:

enter image description here

I don't know why my code is not working. When I pack my bf (bottom frame) and set side = "bottom", but it appears in the middle of the screen. Why? Same with side = "right" when I pack mf (menu frame)

And I have one more question. About logout button. I set command's method "ShowMenu".

When I run my code, this method is started automatically only once, but when I click to button nothing happens. Why?


Solution

  • First, you have a critical flaw in your code. You should not be creating more than one instance of Tk. If you need to create additional windows, create instances of Toplevel.

    When I pack my bf (bottom frame) and set side = "bottom", but it appears in the middle of the screen. Why?

    You set expand to 1 for both mf and mf so each will end up taking half of the available space in the window. If you simply set expand to 0 (zero) or False for bf, it will only take up as much space as necessary.

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

    As a general rule, you should only set a true value for expand on a single widget (the "hero" widget), unless you want to distribute extra space equally among widgets.

    When I run my code, this method is started automatically only once, but when I click to button nothing happens. Why?

    Because you're telling it to run. Take a look at this code:

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

    It is exactly the same as this code:

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

    See the problem?

    The command attribute requires a reference to a function. Roughly translated, that means you can't use (). If you need to pass in an argument to the command, the typical solution is to use functools.partial or lambda to create a reference to an anonymous function that will call the real function with the argument:

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