tkinter frame propagate not behaving?

2024/10/6 20:29:16

If you uncomment the options_frame_title you will see that it does not behave properly. Am I missing something? That section was just copied and pasted from the preview_frame_title and that seems to have no issues.

from tkinter import *blank_app = Tk()
blank_app.geometry('750x500+250+100')
blank_app.resizable(width=False, height=False)main_frame = Frame(blank_app, width=750, height=500, bg='gray22')
main_frame.grid(row=0, column=0, sticky=NSEW)main_title = Label(main_frame, text='App Builder', bg='gray', fg='red', font='Times 12 bold', relief=RIDGE)
main_title.grid(row=0, column=0, padx=2, pady=2, sticky=NSEW, columnspan=2)preview_frame = Frame(main_frame, width=70, height=465, bg='red', highlightcolor='white', highlightthickness=2)
preview_frame.grid(row=1, column=0, padx=2, pady=2, sticky=NSEW)preview_frame_title = Label(preview_frame, text='Preview Window', width=70, bg='gray', fg='blue', relief=RIDGE)
preview_frame_title.grid(row=0, column=0, sticky=NSEW)options_frame = Frame(main_frame, width=240, height=465, bg='blue', highlightcolor='white', highlightthickness=2)
options_frame.grid(row=1, column=1, padx=2, pady=2, sticky=NSEW)options_frame_title = Label(options_frame, text='Widget Options', width=20, bg='gray', fg='blue', anchor=CENTER, relief=RIDGE)
options_frame_title.grid(row=0, column=0, sticky=NSEW)blank_app.mainloop()
Answer

I don't understand what you mean by "behaving properly". It seems to be behaving as it's designed to behave.

By default, tkinter frames are designed to shrink (or grow) to fit their child widgets. When you comment out options_frame_title.grid(...), the frame has no visible children so it says the fixed size that you gave it. When you uncomment that line, it causes a label to be placed in the widget which then causes the frame to shrink to fit.

To further complicate the matters for you, grid will by default give any extra space to rows and columns that have a non-zero weight. Since you haven't given any rows or columns any weight, they don't get any extra space.

Part of the problem is that you are trying to solve too many problems at once. When first starting out you need to be more methodical. Also, you should consider using pack when you're putting a single widget into another widget. It only takes one line of code to get it to fill its parent rather than three with grid.


pro-tip: it really helps if you separate widget creation from widget layout. Your code, even though it's only a couple dozen lines long, is really hard to read.


For example, the first thing you should do is start by creating your top-most frames, and get them to fill and expand/shrink properly before putting any widgets in them.

Starting from scratch

Step 0: don't remove the ability to resize the window

User's don't like having control taken away from them. Remove this line:

blank_app.resizable(width=False, height=False)

Your users will thank you, and during development it's much easier to play with the window to make sure everything is filling, growing, and shrinking as necessary.

Step 1: main_frame

Since it appears this is designed to contain everything, it makes sense to use pack since it is the only widget directly in blank_app.

main_frame = Frame(blank_app, width=750, height=500, bg='gray22')
main_frame.pack(fill="both", expand=True)

With just that (plus the first couple of lines where you create the root window, along with the final call to mainloop), notice how the window is the right size, and the main frame fills the window. You can resize the window all you want and the main frame will continue to fill the whole window.

Step 2: widgets inside main_frame

As I mentioned earlier, it's best to separate widget creation and widget layout. Also, when using grid a good rule of thumb is to always give at least one row and one column a weight. It appears you want the right frame to be about 3x as wide as the left frame. This is where you can use weights.

# widgets in the main frame
main_title = Label(main_frame, text='App Builder', bg='gray', fg='red', font='Times 12 bold', relief=RIDGE)
preview_frame = Frame(main_frame, width=70, height=465, bg='red', highlightcolor='white', highlightthickness=2)
options_frame = Frame(main_frame, width=240, height=465, bg='blue', highlightcolor='white', highlightthickness=2)# laying out the main frame
main_frame.grid_rowconfigure(1, weight=1)
main_frame.grid_columnconfigure(0, weight=1)
main_frame.grid_columnconfigure(1, weight=3)main_title.grid(row=0, column=0, padx=2, pady=2, sticky="nsew", columnspan=2)
preview_frame.grid(row=1, column=0, padx=2, pady=2, sticky="nsew")
options_frame.grid(row=1, column=1, padx=2, pady=2, sticky="nsew")

Once again, run the code and notice that as you resize the main window everything still continues to fill the window, and resize properly, and keep the proper proportions. If you don't like the proportions, just change the weights. They can be any number you want. For example, you could use 70 and 240 if you want.

Step 3: preview frame

The preview frame has a label, and I presume you will be putting other stuff under the label. We'll continue to use grid, and just give the row below the label a weight so that it gets all of the extra space. When you add more widgets, you might need to adjust accordingly.

# widgets in the preview frame
preview_frame_title = Label(preview_frame, text="Preview Window", bg='gray', fg='blue', relief=RIDGE)# laying out the preview frame
preview_frame.grid_rowconfigure(1, weight=1)
preview_frame.grid_columnconfigure(0, weight=1)
preview_frame_title.grid(row=0, column=0, sticky="nsew")

Step 4: the options frame

This is just like the preview frame: a label at the top, and all of the extra space is given to the empty row number 1.

# widgets in the options frame
options_frame_title = Label(options_frame, text='Widget Options', bg='gray', fg='blue', anchor=CENTER, relief=RIDGE)# laying out the options frame
options_frame.grid_rowconfigure(1, weight=1)
options_frame.grid_columnconfigure(0, weight=1)
options_frame_title.grid(row=0, column=0, sticky="new")

Final thoughs

Notice that you don't need to worry about propagation, which is somewhat of an advanced topic. You also don't have to worry about the size of frames since we're using column weights to give relative sizes, and you don't have to give sizes to their labels.

We have removed the propagation code, removed the non-resizable behavior, and removed some hard-coded widths, giving us less code but more functionality.

https://en.xdnf.cn/q/118911.html

Related Q&A

python modules installing Error Visual c++ 14.0 is required [duplicate]

This question already has answers here:pip install ecos errors with "Microsoft Visual C++ 14.0 is required." [duplicate](1 answer)Error "Microsoft Visual C++ 14.0 is required (Unable to …

How to render Flask Web App with Javascript [duplicate]

This question already has answers here:Return JSON response from Flask view(15 answers)How to append ajax html response to next to current div(5 answers)Closed 5 years ago.Edit: Hi Ive checked the dupl…

Use start and stop function with same button in Tkinter

With the help of the command button, I am able to disconnect the frame in Tkinter. But is there any way which helps to use the same button to start also?import tkinter as tk counter = 0 def counter_la…

How to restrict my students to dont access teacher area in django? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.Want to improve this question? Update the question so it focuses on one problem only by editing this post.Closed 4…

invert edge values in python boolean list

I have a list of booleans likel = [False, False, False, True, True, True, False, False, True, False, False]and want to invert every edge value that is False like[True, True, True, True, True, True, Fal…

Unable to write text on mouseclick area on Image

I am trying to draw text on Image where the user clicks. Getting this error:Exception in Tkinter callback Traceback (most recent call last):File "C:\Users\Admin\AppData\Local\Programs\Python\Pytho…

Google Cloud Storage: __init__() got an unexpected keyword argument total_size

I am developping a tool to transcribe interviews for a contract I have. For that I develop a code with the following flow:After input validation, the audio file (in m4a) is converted to wav and stored …

Selenium, Intercept HTTP Request?

Using selenium 4.12 in Python, how can I intercept an HTTP request to see what its body or headers look like? Please Note, that Im not asking for code but rather for resources/ideas of different or su…

Flask server returns 404 on localhost:5000 w/ Twilio

Im following this guide (Python Quickstart: Replying to SMS and MMS Messages) to try and set up a flask server, but when I try to connect to http://localhost:5000 I get a 404 error. I can ping 127.0.0.…

printing values and keys from a dictionary in a specific format (python)

I have this dictionary (name and grade):d1 = {a: 1, b: 2, c: 3}and I have to print it like this:|a | 1 | C | |b | 2 | B | |c | 3 | …