TKInter - The text in the label changes window's width - python

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.

Related

tkinter: adapting label text

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.

Tkinter grids inside grids?

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.

tkinter - Expanding a Listbox inside a Notebook

As the title says, I'm trying to make a Listbox object occupy all space that is inside a Notebook pane.
Here is a screenshot of what I have so far:
What I want to do is to expand the Listbox to occupy all the space that's on the right. I know that if I say listbox['width'] = value to a high enough value, the Notebook panes' titles will not bug this. However I am looking for alternative ways to do this, either resorting to grid() (what I'm using in this project) or pack().
If you're using pack, do it like this:
scrollbar.pack(side="right", fill="y")
listbox.pack(side="left", fill="both", expand=True)
If you're using grid, make sure you call columnconfigure on column 0 and give it a weight that is greater than zero, which will cause it to expand and fill up any extra space in the container.
containing_frame.grid_columnconfigure(0, weight=1)
Try putting sticky = E for the scroll bar grid and then try sticky = EW in the list box.
If that does not work, trying playing around with the column spans of the widgets.

Set the same width to an entry and text tkinter label

I would like to put an entry and a text label one under the other and with the same width.
Here is my code :
from tkinter import *
root = Tk()
title = StringVar()
title_entry = Entry(root, textvariable=title, width=30)
title_entry.pack()
content_text = Text(root, width=30)
content_text.pack()
root.mainloop()
But my 2 widgets don't have the same width. Any idea to solve it ?
The widgets are different sizes probably because they have different default fonts. If they have the same fonts and the same widths, they should have the same natural width. However, the actual width can be affected by how they are placed in the window, and there are often good reasons to use different fonts for these widgets.
The simplest solution in your case is to have each widget fill the container in the x axis. This makes sure that, regardless of their natural width, they will expand to fill the window from edge to edge:
title.pack(fill="x")
content_text.pack(fill="x")
If these are your only two widgets you'll want to go a step further and specify additional options to get proper resize behavior:
title.pack(fill="x")
content_text.pack(fill="both", expand=True)
The width for the Text and Entry widgets is set by the amount of characters. I think, possibly the default font sizes are different for Text and Entry. You may have to set the font sizes in your argument??
You simply need to add a single argument to your .pack attribute. Just put this in:
.pack (fill=X)
Put this in and both widgets will stretch all the width of your window.

Stretching frames using grid layout in Python Tkinter

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.

Categories

Resources