1

I would like to know how I can resize automatically the following gradient frames based on the window size.

from tkinter import *

class InventorySystem:
    def __init__(self, root):
        self.root = root
        self.root.title("Inventory System")
        self.root.geometry("1366x768")

        j = 0
        colors = ["#007F5F", "#2B9348", "#55A630", "#80B918", "#AACC00", "#BFD200",
                  "#D4D700", "#DDDF00", "#EEEF20", "#FFFF3F"]
        for color in colors:
            Frame(self.root, width = 1366 / len(colors), height = 768,
                  bg = color).place(x = j, y = 0)
            j = j + 1366 / len(colors)

if __name__ == "__main__":
    root = Tk()
    application = InventorySystem(root)
    root.mainloop()
martineau
  • 119,623
  • 25
  • 170
  • 301
JackFrost
  • 17
  • 4
  • You could resize the gradient frames in a `''` event callback function bound to the `root` window. – martineau Oct 10 '21 at 16:14
  • Many thanks Martineau. Basically, I am new on Tkinter and in practice I don't know how to use '', I would like to see how someone use it in my code just for understanding the scheme and the mechanism. If you could run and fix the pasted code I will appreciate it otherwise many thanks anyway for the suggestion. – JackFrost Oct 10 '21 at 18:29

2 Answers2

1

What you want to do is somewhat complex, so might be challenging even if you weren't just learning how to use tkinter (only exacerbated by the fact it's so poorly documented). So I've create an example of how to do it based on the code in your question.

One non-intuitive thing (to me) is that the Event handling "callback" function for the <'Configure>' event of a window gets called for the window itself and for all the widgets inside it — which can be very confusing if you don't realize that's what happens.

I've also changed and reformatted your code to more closely follow the PEP 8 - Style Guide for Python Code suggestions, which I strongly suggest your read and start following. Note in particular I changed your wildcard from tkinter import * into the preferrable import tkinter as tk — see Should wildcard import be avoided?

import tkinter as tk

WIDTH, HEIGHT = 1366, 768  # Initial size of root window.

class InventorySystem:
    # Gradient frame colors.
    COLORS = ["#007F5F", "#2B9348", "#55A630", "#80B918", "#AACC00",
              "#BFD200", "#D4D700", "#DDDF00", "#EEEF20", "#FFFF3F"]

    def __init__(self, root):
        self.root = root
        self.root.title("Inventory System")
        self.root.geometry(f'{WIDTH}x{HEIGHT}')
        self.width, self.height = WIDTH, HEIGHT  # Size of root window.
        self.create_gradient_frames()

    def create_gradient_frames(self):
        """Create a gradient frame for each color."""
        self.gradient_frames = []
        colors = self.COLORS  # Alias for local access.
        gradient_frame_width = round(self.width / len(colors))
        gradient_frame_height = self.height

        for i, color in enumerate(colors):
            frame = tk.Frame(self.root, width=gradient_frame_width,
                             height=gradient_frame_height, bg=color)
            frame.place(x=i * gradient_frame_width,
                        y=self.height - gradient_frame_height)
            self.gradient_frames.append(frame)

    def update_gradient_frames(self):
        """Update size and position of all gradient frames."""
        gradient_frame_width = round(self.width / len(self.COLORS))
        gradient_frame_height = self.height

        for i, frame in enumerate(self.gradient_frames):
            frame.config(width=gradient_frame_width, height=gradient_frame_height)
            frame.place(x=i * gradient_frame_width,
                        y=self.height - gradient_frame_height)

    def on_resize(self, event):
        """Root window size change event handler."""
        # Needed following because event handler is called for the container win
        # and all its child widgets but we only need to handle container itself.
        if event.widget.master is not None:  # Not the root window?
            return  # Ignore.

        width, height = root.winfo_width(), root.winfo_height()  # Current size.
        if width != self.width or height != self.height:  # Updated?
            self.width, self.height = width, height  # Track change.
            self.update_gradient_frames()


if __name__ == "__main__":
    root = tk.Tk()
    application = InventorySystem(root)
    root.bind('<Configure>', application.on_resize)  # Bind callback function to event.
    root.mainloop()

Here's a screenshot of the window being resized:

screenshot showing window being resized

martineau
  • 119,623
  • 25
  • 170
  • 301
  • Hello Martineau, I really would like to thank you for your answer, it works perfectly and this will be my starting point for next improvements. My goal is to understand the mechanism behind dinamic resize of widgets and with your kind explaination I believe that I can achieve my goal. Many thanks once again and wish you all the best. PS. Apologize for the poor problem statement! – JackFrost Oct 11 '21 at 08:57
  • JackFrost: Glad to hear you found it helpful with respect to handling the dynamic resizing, even though it's obviously not the simplest way to handle it — as made abundantly clear by @acw1668's answer. `;¬)` – martineau Oct 11 '21 at 16:54
1

You can use relative options of .place():

# relative width of each frame
# 1.0 means same width of parent
relw = 1 / len(colors) 
for j, color in enumerate(colors):
    Frame(self.root, bg=color).place(relx=j*relw, y=0, relwidth=relw, relheight=1)

Refer to official document on place() for details.

acw1668
  • 40,144
  • 5
  • 22
  • 34
  • Many thanks acw1668, your solution is very clear and works perfectly. Wish you a great day and thank you once again... – JackFrost Oct 11 '21 at 09:02
  • @JackFrost: I think you really should accept this answer not mine — it's clearly the better one IMO. – martineau Oct 11 '21 at 10:43