-1

I'm trying to configure a text box and below to the text box 3 buttons in a row centered I don't want to expand them to fill all the area. just be at the center to stay in their original size.

I was trying to do it with pack or grid. but I'm really get confused. I also trying to to put the text box and the buttons on different frame so maybe it will separate the widgets and let me configure it without messing up things (because everything is relative to the other..) ... but I came with nothing that looks good.

I also want to learn how to use the grid in the correct way if I have all kinds of widgets and buttons one below the other without "columnspan" or adjust the text length inside the buttons as well to match the widgets above them...

In this example. How I can center the buttons? I have to use side=tkinter.LEFT in order to put them one after one in a row. but the problem that they also stick to the left...

import tkinter

window = tkinter.Tk()

frame1 = tkinter.Frame(window).pack()

textbox1 = tkinter.Text(frame1, width=70, height=15).pack(side=tkinter.TOP)

button1 = tkinter.Button(frame1, text="button1").pack(side=tkinter.LEFT)
button2 = tkinter.Button(frame1, text="button2").pack(side=tkinter.LEFT)
button3 = tkinter.Button(frame1, text="button3").pack(side=tkinter.LEFT)

window.mainloop()

in this example if I set another frame to do separation between the widgets ... It's not get to the center either....

import tkinter

window = tkinter.Tk()

frame1 = tkinter.Frame(window).pack(side=tkinter.TOP)

textbox1 = tkinter.Text(frame1, width=70, height=15).pack(side=tkinter.TOP)

frame2 = tkinter.Frame(window).pack(side=tkinter.TOP)

button1 = tkinter.Button(frame2, text="button1").pack(side=tkinter.LEFT)
button2 = tkinter.Button(frame2, text="button2").pack(side=tkinter.LEFT)
button3 = tkinter.Button(frame2, text="button3").pack(side=tkinter.LEFT)

window.mainloop()

And in this example. with grid, if I'm using different frames the button just jump on the text box and messed up everything....

import tkinter

window = tkinter.Tk()

frame0 = tkinter.Frame(window).grid(row=0, column=0)

frame1 = tkinter.Frame(window).grid(row=1, column=0)

textbox = tkinter.Text(frame0, width=70, height=15).grid(row=0, column=0)

button1 = tkinter.Button(frame1, text="button1").grid(row=0, column=0)
button2 = tkinter.Button(frame1, text="button2").grid(row=0, column=1)
button3 = tkinter.Button(frame1, text="button3").grid(row=0, column=2)

window.mainloop()

Can someone explain to me please in which way it's better to use and how to understand it better...? it's always confusing me...

thanks in advance, eliran

  • Read up on [AttributeError: NoneType object has no attribute](https://stackoverflow.com/a/1101765/7414759), [The Tkinter Grid Geometry Manager](http://effbot.org/tkinterbook/grid.htm) and [The Tkinter Pack Geometry Manager](http://effbot.org/tkinterbook/pack.htm) – stovfl Jun 18 '20 at 11:40

2 Answers2

0

I was trying to do it with pack or grid. but I'm really get confused. I also trying to to put the text box and the buttons on different frame so maybe it will separate the widgets and let me configure it without messing up things (because everything is relative to the other..) ... but I came with nothing that looks good.

Your second example is fairly close to working, but it has a fatal flaw. If you add some debugging statements you'll see that frame1 and frame2 are None. Thus, any widgets with those as a parent actually end up in the root window.

This is because foo().bar() always returns the result of .bar(). In tkinter, .grid(...) always returns None, so Frame(...).grid(...) will always return None.

The best practice is to always separate widget creation from widget layout. For example:

frame1 = tkinter.Frame(window)
frame2 = tkinter.Frame(window)

frame1.pack(side="top")
frame2.pack(side="top")

With that, frame1 and frame2 are properly set to the frames. And when that happens, the rest of the code in your second example works as you expect and the buttons are centered.

And in this example. with grid, if I'm using different frames the button just jump on the text box and messed up everything....

That happens for the same reason as mentioned above: you think you're using separate frames, but everything is going in the root window. Because they are all in the root window, and you put the text widget and a button in the same row and column, they overlap.

I also want to learn how to use the grid in the correct way if I have all kinds of widgets and buttons one below the other without "columnspan" or adjust the text length inside the buttons as well to match the widgets above them...

grid is not the right choice in this specific case, since you aren't actually creating a grid. You can use it, but it requires more code than using pack. grid is the right choice if you're creating an actual grid. In this case you aren't.

Using grid in this case requires a little creativity. While it's not the only solution, I would recommend that you divide the bottom frame into five columns - an empty column on the left and right, and three columns in the middle for the buttons. The empty columns can be used to take up all extra space, forcing the middle columns to all be centered.

A best practice for using grid is that every window that uses grid to manage its children needs at least one row and one column with a non-zero weight. That lets tkinter know where to allocate any extra space, such as when the user resizes the window.

Here's a complete solution using grid:

import tkinter

window = tkinter.Tk()

frame0 = tkinter.Frame(window)
frame1 = tkinter.Frame(window)

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

frame0.grid(row=0, column=0, sticky="nsew")
frame1.grid(row=1, column=0, sticky="nsew")

frame0.grid_rowconfigure(0, weight=1)
frame0.grid_columnconfigure(0, weight=1)

textbox = tkinter.Text(frame0, width=70, height=15)
textbox.grid(row=0, column=0, sticky="nsew")

button1 = tkinter.Button(frame1, text="button1")
button2 = tkinter.Button(frame1, text="button2")
button3 = tkinter.Button(frame1, text="button3")

frame1.grid_rowconfigure(0, weight=1)
frame1.grid_columnconfigure((0,4), weight=1)

button1.grid(row=0, column=1)
button2.grid(row=0, column=2)
button3.grid(row=0, column=3)

window.mainloop()

Can someone explain to me please in which way it's better to use and how to understand it better...?

In summary, your instinct to use separate frames is the right place to start. You should divide your UI into logical groups, and use separate frames for each group. Then, you are free to pick either grid or pack for each group separately. However, you need to be diligent with grid to make sure that the sticky option is used correctly, and that you've set weights for all of the right columns.

And finally, you have to start with the proper practice of separating widget creation from widget layout.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Wow.Really thanks for your detailed explanation in deep. I will try to practice it more - the separation, weight and sticky.. all of it. The complete solution you wrote is exactly what I was trying to get. You said that I'm not really creating a grid in this example (what is the right definition to grid).. I'm interesting to see different kind of layouts examples that are more "easy" \ "right" to use with .pack() and others that are more comfortable to choose working with grid.() –  Jun 19 '20 at 09:39
-2

I have had these kinds of problems before. Even though the .pack() and .grid() systems are excellent, when things are getting hectic you can use the .place() system. .place() allows you to exactly pin-point your tkinter and ttk widgets using x-y axis coordinates.

The coordinates (0,0) are not at the center but at the topmost left corner of your tkinter window.

Eg:

some_widget_name = Button(root, text="Click me!"....)
some_widget_name.place(x=100, y=50)

This will make your widget move right 100 pixels and move down 50 pixels from the topmost left corner.

However, sometimes when you really want to make the location of the widgets precise, you may have to do some trial-and-error to make it visually pleasing.

Pranav Krishna S
  • 324
  • 2
  • 13
  • Thanks for your replay.! Yeah, I already used .place() when I placed some png images on canvas, it's great.. But the problem is when you want to move them \ add more widgets to your gui, you have to play with the coordinates again...and you have to do it visually (trial-and-error) because it's hard to predict where it will be located, very frustrating when you want do something to look accurate. So this why sometimes I think to void the .place(). I think it's much better when you really plan in advance your interface how it's gonna look. –  Jun 19 '20 at 09:12