I'm trying to get stretching to work using Python 2.6.7 with Tkinter. I'd expect the below code to stretch the first button to the width of the second, but both buttons are only as wide as they need to be to fit their text.
#!/usr/bin/python
from Tkinter import *
win = Frame()
win.grid(sticky=N+S+E+W)
inner_a = Frame(win)
inner_a.grid(row=0, column=0, sticky=N+E+W)
inner_b = Frame(win)
inner_b.grid(row=1, column=0, sticky=S+E+W)
Button(inner_a, text='1').grid(row=0, column=0, sticky=E+W)
Button(inner_b, text='Some long text').grid(row=0, column=0, sticky=E+W)
win.mainloop()
By my understanding, the single column in win will expand to the width of the largest thing it contains, ie the width of inner_b, and then the width of inner_a, and thence of the first button, will be that of the second button.
Actually, what happens is the below; the first button is only wide enough to contain "1", not as wide as the second button.
What do I need to do to get the first button to expand the size of the second?
If you want widgets to line up in a grid, the first thing to do is make sure they have the same parent. This isn't strictly necessary if all the widgets are the same size or you are only using one column.
Another thing you need to do is give your column a weight. What is happening in your code is that the widget is expanding to fill the column, but the column isn't expanding to fill the master. If you give it a weight of 1 it will. You ned to do something like inner_a.columnconfigure(1, weight=1), and then do likewise for inner_b.
Related
I have a frame and I want it to be a certain size (relative to the root window). When I pack in a label with text big enough to make the label bigger than the frame that contains it, the frame expands. How do I prevent the frame from expanding and make the words that don't fit into one line just go into the next line. I need a solution different than simply adding \n because in my actual project the text is dependant on the users input.
from tkinter import *
root = Tk()
root.geometry("300x300")
f = Frame(root,width=100, height=50, bg="yellow")
f.place(relx=0.5, rely=0.5, anchor=CENTER)
Label(f, text="this is a veeeeeery looooong text").pack(side=LEFT)
root.mainloop()
If you want the label to be a fixed size you can specify a size for the label. Tkinter will do its best to honor the requested size. Of course, that means that long text will be chopped off in the label.
Label(f, width=4, text="this is a veeeeeery looooong text").pack(side=LEFT)
With that, the frame will shrink if it's larger than the space required by the label, but it won't grow since the label itself won't grow.
If you want the label to have no effect on the frame at all, you can turn geometry propagation off for the frame. By turning it off, you are telling tkinter to honor the requested size of the frame and not let the size of the children override that.
f.pack_propagate(False)
This is rarely a good idea since tkinter is really good at computing the optimal size, but there are some rare occassions where it is exactly the right thing to do.
I would really appreciate some help with figuring out grid geometry manager.
Here is what I want to build.
I was thinking of using grid but I cannot find any good tutorials that would clearly
explain how to work with it.
There are lots of tutorials but mostly all are either very simple or really outdated.
I am not sure how to build what is shown in the picture using only grid because all
elements are nested inside each other and each element is supposed to hold more elements inside it.
It's not so hard to arrange outermost widgets using grid. I just place Toolbar into 0th row,
then outermost PanedWidow (green) into 1st row, and then Status Bar into 2nd row.
After that I need to arrange things inside green PanedWindow.
I place another PanedWindow (pink) into the right pane of the green PanedWindow and then
stick a Notebook into it's top pane.
Now, I need to add more widgets to these inner panes. For instance. I am going to add
some buttons to the bottom pane of the pink PanedWindow. And that's where I run into problems.
If I try to use pack() to arrange things inside these innermost panes, Python screams at me for
using more than one geometry manager.
But when I think about how to accomplish this with grid, I just can't find a way to subdivide
innermost panes into smaller grids.
Can there be grids inside Widgets which have been acted upon by an outer grid?
When I see widgets that take up the full width or full height of an area I usually use pack since since it's specifically designed to lay objects along a side of an empty cavity. You can use grid but it requires extra code since you have to both add the widget and configure the rows and columns. With pack all you have to do is add the widgets.
For example, it's clear you want a statusbar along the bottom, and a toolbar along the time, and a paned widget in-between. So, start with that, as in the following example:
import tkinter as tk
root = tk.Tk()
root.geometry("600x400")
toolbar = tk.Frame(root, background="#d5e8d4", height=40)
statusbar = tk.Frame(root, background="#e3e3e3", height=20)
main = tk.PanedWindow(root, background="#99fb99")
toolbar.pack(side="top", fill="x")
statusbar.pack(side="bottom", fill="x")
main.pack(side="top", fill="both", expand=True)
root.mainloop()
Note: widths, heights, and colors are added to the frame for illustrative purposes since otherwise, an empty frame would have a size of 1x1. Once you add widgets inside a frame you can remove the width and height options.
You say the right will have a paned window, so add that on the right. We'll use a normal frame on the left.
left_pane = tk.Frame(main, background="#99fb99", width=100)
right_pane = tk.PanedWindow(main, background="#99fb99", width=200)
main.add(left_pane)
main.add(right_pane)
Next, add the two panes to the right. So that I can show colors with as little code as possible I'll use a frame on the top instead of a notebook:
notebook = tk.Frame(right_pane, background="#99ceff", height=70)
bottom_right = tk.Frame(right_pane, background="#ffe6cd", height=50)
right_pane.add(notebook)
right_pane.add(bottom_right)
With all that being said, you can use grid if you want. The trick is to use intermediate frames, since the layout in any widget is independent of the layout in parent or child widgets.
All you need to do is remove the first three calls to pack and replace it with these five lines:
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
toolbar.grid(row=0, column=0, sticky="ew")
main.grid(row=1, column=0, sticky="nsew")
statusbar.grid(row=2, column=0, sticky="ew")
Since the other widgets are children of paned widgets, there's nothing else to do. Any widgets you add to each pane have their own independent layout area, so you can use grid, pack, or place inside each frame.
To illustrate that point, I'll use grid to add several rows and columns of squares:
for row in range(6):
for column in range(30):
f = tk.Frame(bottom_right, background="white",
bd=2, relief="raised", width=10, height=10)
f.grid(row=row, column=column)
I found a post that's around two years old, which might be a little too old for your uses, but it has some information on nesting grids in Tkinter. It recommends using frames to nest the grids, essentially having children within children of a frame. Within these frames, you can place objects.
I got this Text widget, and I'd like for it to expand and fill its entire parent, using the Grid geometry manager.
According to the examples I've seen, this sample program should work, alas it doesn't, when expanding the window, the contents are not resizing.
from Tkinter import *
root = Tk()
input_text_area = Text(root)
input_text_area.grid(row=1, column=0, columnspan=4, sticky=W+E)
input_text_area.configure(background='#4D4D4D')
root.mainloop()
Any help is appreciated
For what it's worth, I'm running in Python 2.7 (latest 2.x version), and coding in PyCharm, though I don't think the IDE is relevant.
When using grid, any extra space in the parent is allocated proportionate to the "weight" of a row and/or a column (ie: a column with a weight of 2 gets twice as much of the space as one with a weight of 1). By default, rows and columns have a weight of 0 (zero), meaning no extra space is given to them.
You need to give the column that the widget is in a non-zero weight, so that any extra space when the window grows is allocated to that column.
root.grid_columnconfigure(0, weight=1)
You'll also need to specify a weight for the row, and a sticky value of N+S+E+W if you want it to grow in all directions.
Since your window only contains one widget and you want this widget to fill the entire window, it would be easier to use the pack geometry manager instead of grid
input_text_area.pack(expand=True, fill='both')
expand=True tells Tkinter to allow the widget to expand to fill any extra space in the geometry master. fill='both' enables the widget to expand both horizontally and vertically.
from tkinter import *
root = Tk()
input_text_area = Text(root)
input_text_area.grid(row=0, column=0, columnspan=4, sticky=N+S+W+E)
input_text_area.configure(background='#4D4D4D')
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(0, weight=1)
root.mainloop()
not sure if this is what you want.
but this fills the entire screen.
I got this Text widget, and I'd like for it to expand and fill its entire parent, using the Grid geometry manager.
According to the examples I've seen, this sample program should work, alas it doesn't, when expanding the window, the contents are not resizing.
from Tkinter import *
root = Tk()
input_text_area = Text(root)
input_text_area.grid(row=1, column=0, columnspan=4, sticky=W+E)
input_text_area.configure(background='#4D4D4D')
root.mainloop()
Any help is appreciated
For what it's worth, I'm running in Python 2.7 (latest 2.x version), and coding in PyCharm, though I don't think the IDE is relevant.
When using grid, any extra space in the parent is allocated proportionate to the "weight" of a row and/or a column (ie: a column with a weight of 2 gets twice as much of the space as one with a weight of 1). By default, rows and columns have a weight of 0 (zero), meaning no extra space is given to them.
You need to give the column that the widget is in a non-zero weight, so that any extra space when the window grows is allocated to that column.
root.grid_columnconfigure(0, weight=1)
You'll also need to specify a weight for the row, and a sticky value of N+S+E+W if you want it to grow in all directions.
Since your window only contains one widget and you want this widget to fill the entire window, it would be easier to use the pack geometry manager instead of grid
input_text_area.pack(expand=True, fill='both')
expand=True tells Tkinter to allow the widget to expand to fill any extra space in the geometry master. fill='both' enables the widget to expand both horizontally and vertically.
from tkinter import *
root = Tk()
input_text_area = Text(root)
input_text_area.grid(row=0, column=0, columnspan=4, sticky=N+S+W+E)
input_text_area.configure(background='#4D4D4D')
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(0, weight=1)
root.mainloop()
not sure if this is what you want.
but this fills the entire screen.
I'm building a calculator in python, using the tkinter toolkit. The problem is that when the text is typed in the calculator (and added to the label that shoes the calculation) the whole width of the window changes and becomes longer. What can I do in order to solve it?
Here is some important parts of the code: (the main class inherits from tk.Frame)
labelStyle = {"padx":10, "pady":10, "justify":"left"}
calculationsLabel = tk.Label(self, text="", **labelStyle)
calculationsLabel.grid(row=0, column=1, **gridStyle)
self.master.resizable(0,0)
self.pack(padx=5, pady=5)
self.calculationsLabel=calculationsLabel
for number in range(9,0,-1):
...
tk.Button(self, ...).grid(...)
The images that illustrates the problem:
You need to do a couple of things to prevent the label from changing the window size:
Give the label a width of 1 (one). By not giving the label a width you are implicitly saying "grow bigger when the text is bigger". By giving it an explicit width you are saying "no matter how big the text is, don't grow if the text is bigger".
use the columnspan option to grid, to get the cell that the label is in to span the width of your grid of buttons. Use the sticky option, so that even though the label requests only one character of width, grid will force it to grow wide enough to fit the space.
You can use the columnspan argument to let the label stretch over top all of your columns, instead of stretching out the first one. Add to your grid method:
calculationsLabel.grid(row=0, column=1, columnspan=7 **gridStyle)
(replacing 7 with however many columns you actually have)
You could use the columnspan option of grid to make the label span the complete width of the calculator.
Then, if you want the number to be on the left use anchor=W in the Label.
This way the window only expands when the Label is longer than the complete window. And you can even prevent that by using the Label's width option.