2

I am trying to create 16 buttons which will completely occupy the bottom 3/4 th of the window. But, the frame height and width values don't seem to have any effect. How to get the behaviour I want?

from tkinter import *


class Application(object):
    def __init__(self):
        # Creating the main window
        self.window = Tk()
        self.window.geometry('{}x{}'.format(400, 400))

        # frame where numbered buttons will be
        frame = Frame(self.window)
        frame.configure(height=300, width=300)
        frame.pack(side=BOTTOM)

        # add buttons
        for i in range(4):
            for j in range(4):
                Button(frame, text=str(4*i + j + 1)).grid(row=i, column=j, sticky=N+E+S+W)
        self.window.mainloop()


def main():
    app = Application()

main()
Sounak
  • 4,803
  • 7
  • 30
  • 48
  • pass an argument `master` in to `__init__` and then change the resizing line to `master.geometry('{}x{}'.format(400, 400))` that should work – WhatsThePoint Apr 27 '17 at 14:55
  • @WhatsThePoint I didn't really understand what you meant. Can you elaborate a bit? – Sounak Apr 27 '17 at 14:57
  • @Bryan Oakley Adding `self.window.pack_propagate(0)` does not fix the issue. – Sounak Apr 27 '17 at 15:04
  • @SadhuBaba: `pack_propagate(0)` is almost never the right solution. Tkinter's default behavior almost always gives you a UI that is easier to write, and is more responsive to changes in fonts and resolutions and window sizes. If you want buttons to occupy the bottom 3/4ths of the window, there are better ways to achieve that than with fixed frame sizes. – Bryan Oakley Apr 27 '17 at 15:09
  • 1
    Because the root problem is the same. Tkinter widgets are designed to shrink (or expand) to fit their children. Thus, if you apply a size to a frame and then place widgets inside that frame, the frame is going to shrink to fit. You asked what is wrong, and the answer is that nothing is wrong -- this is the default behavior of Tkinter. – Bryan Oakley Apr 27 '17 at 15:11
  • @BryanOakley How to get the behaviour I want? – Sounak Apr 27 '17 at 15:12
  • 1
    I recommend you rephrase your question to ask what you really want. To me it sounded like you were asking why the UI was behaving this way. If you don't care why, but actually want to know how to divide your main window into two sections where one is 1/4 of the screen and one is 3/4, ask that instead. – Bryan Oakley Apr 27 '17 at 15:17
  • 1
    Grid columns and rows can be configured to have a minimum size in pixels. `frame.grid_columnconfigure(i, minsize=75)`, `frame.grid_rowconfigure(j, minsize=75)`. – mike.k Apr 27 '17 at 15:24

1 Answers1

1

The reason for the behavior you are seeing is that tkinter widgets are designed to shrink or expand to exactly fit around their children when using grid or pack. 99.99% of the time this is the exact right behavior, because it results in GUIs that are responsive to changes in font size, screen resolution, and window size.

If your goal is to divide the screen into two parts, where one part takes up 1/4 of the screen and one part takes up 3/4, the best solution is to use grid or place since those both make it easy to set relative sizes.

I don't normally recommend place, so here's a solution using grid. Note the use of grid.rowconfigure and grid.columnconfigure

from tkinter import *

class Application(object):
    def __init__(self):
        self.window = Tk()
        self.window.geometry('{}x{}'.format(400, 400))

        self.window.grid_rowconfigure(0, weight=1)
        self.window.grid_rowconfigure(1, weight=3)
        self.window.grid_columnconfigure(0, weight=1)

        frame = Frame(self.window, background="pink")
        frame.grid(row=1, column=0, sticky="nsew")

        for row in range(4):
            frame.grid_rowconfigure(row, weight=1)
        for column in range(4):
            frame.grid_columnconfigure(column, weight=1)

        # add buttons
        for i in range(4):
            for j in range(4):
                button = Button(frame, text=str(4*i + j + 1))
                button.grid(row=i, column=j, sticky=N+E+S+W)
        self.window.mainloop()


def main():
    app = Application()

main()

With this example, row 0 (zero) in the root window can be used for anything you want. Tkinter will try its best to always make that part of the GUI 1/4 the height of the window. I recommend putting a frame in that row, and then any other widgets inside that frame.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Would you please add an explanation of what exactly `grid_rowconfigure` and `grid_columnconfigure` is doing? What does the`weight` paramater do? – Sounak Apr 27 '17 at 15:39
  • @SadhuBaba: those methods and options are documented in many places. For example http://www.tkdocs.com/tutorial/grid.html and http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/grid-config.html. There are also plenty of questions on stackoverflow related to using `grid`. – Bryan Oakley Apr 27 '17 at 15:45