Second window resizes, when moving Main window

this is only a brain exercise for a 72 yo…coding may be messy, but it works..lol
What happens is after generating the random numbers, if you drag the main window, to a new location, the second window resizes…how can I stop it happening.

import random
import tkinter as tk
from tkinter import messagebox

second_window = None
# --- Tkinter root Setup ---
root = tk.Tk()

root.title("Unique Random Number Generator")

# Define root width and height
root_width = 400
root_height = 200

monitor_offset_x = 1920  # Change to 0 for primary, or negative for left monitor
monitor_width = 1920     # Width of target monitor
monitor_height = 1080    # Height of target monitor

# Calculate centered coordinates on target monitor
x = monitor_offset_x + (monitor_width // 2) - (root_width // 2)
y = (monitor_height // 2) - (root_height // 2)

# 3. Apply geometry to the main window
root.geometry(f"{root_width}x{root_height}+{x + 50}+{y -300}")

# Center the root
# center_on_main_screen(root, root_width, root_height)


# Total Count Input
lbl_1 = tk.Label(root, text="How many numbers?")
lbl_1.grid(row=0, column=0, padx=10, pady=1, sticky="w")
entry_count = tk.Entry(root, width = 5, justify="center", font=("Arial", 12, "bold"))
entry_count.insert(0, "")  # Default value
entry_count.grid(row=0, column=0, padx=150, pady=1, sticky="w")

# Start Range Input
lbl_2 = tk.Label(root, text="Minimum Value:")
lbl_2.grid(row=1, column=0, padx=10, pady=1, sticky="w")
entry_start = tk.Entry(root, width = 5, justify="center", font=("Arial", 12, "bold"))
entry_start.insert(0, "")  # Default value
entry_start.grid(row=1, column=0, padx=150, pady=1, sticky="w")

# End Range Input
lbl_3 = tk.Label(root, text="Maximum Value:")
lbl_3.grid(row=2, column=0, padx=10, pady=1, sticky="w")
entry_end = tk.Entry(root, width = 5, justify="center", font=("Arial", 12, "bold"))
entry_end.insert(0, "")  # Default value
entry_end.grid(row=2, column=0, padx=150, pady=1, sticky="w")

# inserts blank rows to position "Results"
space_1 = tk.Label(root,text="  ")
space_1.grid(row=3, column =0)
space_2 = tk.Label(root,text="  ")
space_2.grid(row=4, column =0)
space_3 = tk.Label(root,text="  ")
space_3.grid(row=5, column =0)


# def center_on_main_screen(root, width, height):
    # Temporarily hide to avoid drawing in the wrong spot initially
root.withdraw()
root.update_idletasks()
 
#    root_height = 200
#       
# Calculate exact center offsets
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()    
    
x_offset = int((screen_width - root_width) / 2)
y_offset = int((screen_height - root_height) / 2)
    # Set the geometry and make the root visible again
root.geometry(f"{root_width}x{root_height}+{x_offset+1000}+{y_offset-300}")
root.deiconify()
    
def generate_unique_numbers():
    try:
# Retrieve values from entry boxes
        count = int(entry_count.get())
        start = int(entry_start.get())
        end = int(entry_end.get())
        
# Validation check: Total available numbers must be >= requested count
        if count > (end - start + 1):
            messagebox.showerror(
                "Error", "Range is too small to generate unique numbers!"
            )
            return

# random.sample picks unique numbers without duplicates
        unique_numbers = random.sample(range(start, end + 1), count)
        
# Display the result in the label
        label_result.config(fg="green", text=f"Result: {start}")
        
        for i, num in enumerate(unique_numbers, start=1):
            print(f"Position {i}: {num}")

# Create and position the second window
        global second_window      
        second_window = tk.Toplevel(root)
        second_window.title("Your Numbers Are:")
#        tk.Label(second_window, text="This root is at the bottom")   
        second_window_width = 600
        second_window_height = 60
# Keep this window on top of all other windows (including the main window)
    # without freezing the main window's usage
        second_window.attributes('-topmost', True)
# Create Second root (second_window)                    
        second_window.overrideredirect(True)  
        def update_position(event=None):
# Get main root coordinates and dimensions
            root_width = root.winfo_width()
#            root_height = root.winfo_height()
            root_x = root.winfo_rootx()
            root_y = root.winfo_rooty() + root.winfo_height()        
# Calculate centered X coordinate
            pos_x = root_x + (root_width // 2) - (second_window_width // 2)        
 
# Calculate bottom-aligned Y coordinate
            pos_y = root_y - second_window_height
# Apply geometry to the second root
            second_window.geometry(f"{second_window_width}x{second_window_height}+{pos_x}+{pos_y}")
# Bind the configure event to track moves and resizes
        root.bind("<Configure>", update_position) 
# Place List into Boxes in Second root
        for index, number in enumerate(unique_numbers):
            row_num = index // 10
#            target_row = row_num
            col_num = index % 10
            print(f"Row Number: {row_num}")
            new_height = second_window.winfo_reqheight() + 25            
            second_window.geometry(f"{second_window_width}x{new_height}")
            second_window.update_idletasks()
            entry_box2 = tk.Entry(second_window, width=5, font=('Arial', 14), bg="#4CAF50",fg="white", justify='center')    
        # Precise positioning on a row-by-row basis
            entry_box2.grid(row=row_num, column=col_num,padx=2, pady=2)                 
        # Place the unique number into the box
            entry_box2.insert(0, str(number))
            entry_box2.config(state="readonly", readonlybackground="#4CAF50")

    except ValueError:
        messagebox.showerror("Input Error", "Please enter valid integers.")

# Results Output Label
label_result = tk.Label(
    root, text="Your Numbers Will Appear Here!", font=("Arial", 12, "bold"), fg="#333333")
label_result.grid(row=6, column=0, padx=25, pady=1, sticky="w")

# Generates Random Numbers Button
btn_1 = tk.Button(root, padx = 18, text='Generate', font=("Arial", 12, "bold"), command = generate_unique_numbers,
    bg="#4CAF50",
    fg="white",)
btn_1.place(x=250, y=10)

# Clears In/Out Fields
def reset_fields():
# Resets Main Window Input Fields
    entry_count.delete(0, tk.END)
    entry_start.delete(0, tk.END)
    entry_end.delete(0, tk.END)
    label_result.config(text="Your Numbers Will Appear Here!", font=("Arial", 12, "bold"), fg="#333333")
# 1ms delay, to Close Window 2
    second_window.after(100, second_window.destroy)

# Reset Button
btn_2 = tk.Button(root, padx = 30, text='Reset', font=("Arial", 12, "bold"), command = reset_fields, 
    bg="#f3a72f",
    fg="black",)
btn_2.place(x=250, y=50)

# Reset Button
btn_3 = tk.Button(root, padx = 22, text='Exit', width=1, font=("Arial", 12, "bold"), command = root.destroy, 
    bg="#FFDF20",
    fg="black",)
btn_3.place(x=300, y=100)


# Keep root open
root.mainloop()

Hi Laurie,

Kudos on building this -Tkinter geometry management across multiple windows can definitely get tricky!

The resizing happens because your <Configure> handler is changing the size of second_window every time the main window moves.

Inside generate_unique_numbers() you initially have:

second_window_height = 60

Then, inside your loop, you repeatedly increase the popup’s height:

new_height = second_window.winfo_reqheight() + 25
second_window.geometry(f"{second_window_width}x{new_height}")

So the popup ends up being taller than 60 pixels.

However, when you drag the main window, Tkinter generates a <Configure> event, which calls update_position(). That function runs:

second_window.geometry(
    f"{second_window_width}x{second_window_height}+{pos_x}+{pos_y}"
)

Since second_window_height is still 60, you are inadvertently telling Tkinter: “Move the window, and force it back to 60 pixels high.” That is why it abruptly shrinks whenever the main window moves.

A simple fix

Let Tkinter calculate the popup’s requested height once after all entries are placed, and then have update_position() update only the position, keeping the calculated size fixed:

# Create all the entry widgets first
for index, number in enumerate(unique_numbers):
    row_num = index // 10
    col_num = index % 10

    entry_box2 = tk.Entry(
        second_window,
        width=5,
        font=('Arial', 14),
        bg="#4CAF50",
        fg="white",
        justify='center'
    )
    entry_box2.grid(row=row_num, column=col_num, padx=2, pady=2)
    entry_box2.insert(0, str(number))
    entry_box2.config(
        state="readonly",
        readonlybackground="#4CAF50"
    )

# Let Tkinter calculate the requested size once
second_window.update_idletasks()

popup_width = 600
popup_height = second_window.winfo_reqheight()


def update_position(event=None):
    if second_window is None or not second_window.winfo_exists():
        return

    root_width = root.winfo_width()
    root_x = root.winfo_rootx()
    root_y = root.winfo_rooty() + root.winfo_height()

    pos_x = root_x + (root_width // 2) - (popup_width // 2)
    pos_y = root_y - popup_height

    # Only the position changes; the calculated size stays the same
    second_window.geometry(
        f"{popup_width}x{popup_height}+{pos_x}+{pos_y}"
    )


update_position()
root.bind("<Configure>", update_position)

I’d also recommend adding a quick guard inside reset_fields(), since second_window is initially None:

def reset_fields():
    global second_window

    entry_count.delete(0, tk.END)
    entry_start.delete(0, tk.END)
    entry_end.delete(0, tk.END)

    label_result.config(
        text="Your Numbers Will Appear Here!",
        font=("Arial", 12, "bold"),
        fg="#333333"
    )

    if second_window is not None and second_window.winfo_exists():
        second_window.destroy()
        second_window = None

This ensures clicking “Reset” before generating any numbers won’t try to call winfo_exists() on None.

Hi David, thank you so much, especially with the included explanation…your method “works,” but, I don’t know if I’ve caused it…when moving the main window (root) the “popup” window’s height, is fixed at 200.. this normally would not be an issue, but as a learning exercise, I like to know what causes it, and how to stop it fixing its height…my test was
How Many Numbers?: 40
Minimum Value: 1
Maximum Value: 100

and

How Many Numbers?: 80
Minimum Value: 1
Maximum Value: 100

NB..there a a few “Print” functions..they are only to help me understand what is happening.

regards
Laurie

import random
import tkinter as tk
from tkinter import messagebox

second_window = None
# --- Tkinter root Setup ---
root = tk.Tk()

root.title("Unique Random Number Generator")

# Define root width and height
root_width = 400
root_height = 200

monitor_offset_x = 1920  # Change to 0 for primary, or negative for left monitor
monitor_width = 1920     # Width of target monitor
monitor_height = 1080    # Height of target monitor

# Calculate centered coordinates on target monitor
x = monitor_offset_x + (monitor_width // 2) - (root_width // 2)
y = (monitor_height // 2) - (root_height // 2)

# 3. Apply geometry to the main window
root.geometry(f"{root_width}x{root_height}+{x + 50}+{y -300}")

# Center the root
# center_on_main_screen(root, root_width, root_height)


# Total Count Input
lbl_1 = tk.Label(root, text="How many numbers?")
lbl_1.grid(row=0, column=0, padx=10, pady=1, sticky="w")
entry_count = tk.Entry(root, width = 5, justify="center", font=("Arial", 12, "bold"))
entry_count.insert(0, "")  # Default value
entry_count.grid(row=0, column=0, padx=150, pady=1, sticky="w")

# Start Range Input
lbl_2 = tk.Label(root, text="Minimum Value:")
lbl_2.grid(row=1, column=0, padx=10, pady=1, sticky="w")
entry_start = tk.Entry(root, width = 5, justify="center", font=("Arial", 12, "bold"))
entry_start.insert(0, "")  # Default value
entry_start.grid(row=1, column=0, padx=150, pady=1, sticky="w")

# End Range Input
lbl_3 = tk.Label(root, text="Maximum Value:")
lbl_3.grid(row=2, column=0, padx=10, pady=1, sticky="w")
entry_end = tk.Entry(root, width = 5, justify="center", font=("Arial", 12, "bold"))
entry_end.insert(0, "")  # Default value
entry_end.grid(row=2, column=0, padx=150, pady=1, sticky="w")

# inserts blank rows to position "Results"
space_1 = tk.Label(root,text="  ")
space_1.grid(row=3, column =0)
space_2 = tk.Label(root,text="  ")
space_2.grid(row=4, column =0)
space_3 = tk.Label(root,text="  ")
space_3.grid(row=5, column =0)


# def center_on_main_screen(root, width, height):
    # Temporarily hide to avoid drawing in the wrong spot initially
root.withdraw()
root.update_idletasks()
 
#    root_height = 200
#       
# Calculate exact center offsets
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()    
    
x_offset = int((screen_width - root_width) / 2)
y_offset = int((screen_height - root_height) / 2)
    # Set the geometry and make the root visible again
root.geometry(f"{root_width}x{root_height}+{x_offset+1000}+{y_offset-300}")
root.deiconify()
    
def generate_unique_numbers():
    try:
# Retrieve values from entry boxes
        count = int(entry_count.get())
        start = int(entry_start.get())
        end = int(entry_end.get())
        
# Validation check: Total available numbers must be >= requested count
        if count > (end - start + 1):
            messagebox.showerror(
                "Error", "Range is too small to generate unique numbers!"
            )
            return

# random.sample picks unique numbers without duplicates
        unique_numbers = random.sample(range(start, end + 1), count)
        
# Display the result in the label
        label_result.config(fg="green", text=f"Result: {start}")
        
        for i, num in enumerate(unique_numbers, start=1):
            print(f"Position {i}: {num}")

# Create and position the second window
        global second_window      
        second_window = tk.Toplevel(root)
        second_window.title("Your Numbers Are:")
#        tk.Label(second_window, text="This root is at the bottom")   
        second_window_width = 600
#        second_window_height = 60
# Keep this window on top of all other windows (including the main window)
    # without freezing the main window's usage
        second_window.attributes('-topmost', True)
# Create Second root (second_window)                    
        second_window.overrideredirect(True)
        # Let Tkinter calculate the requested size once
        second_window.update_idletasks()
        popup_width = 600
        popup_height = second_window.winfo_reqheight()
        def update_position(event=None):
            if second_window is None or not second_window.winfo_exists():
                return
# Get main root coordinates and dimensions
            root_width = root.winfo_width()
#            root_height = root.winfo_height()
            root_x = root.winfo_rootx()
            root_y = root.winfo_rooty() + root.winfo_height()        
# Calculate centered X coordinate
            pos_x = root_x + (root_width // 2) - (popup_width // 2)        
 
# Calculate bottom-aligned Y coordinate
            pos_y = root_y - popup_height
            print(f": {print(f"Popup Height: {popup_height}")}")
# Apply geometry to the second root
            second_window.geometry(f"{popup_width}x{popup_height}+{pos_x}+{pos_y + 150}")
        update_position()
# Bind the configure event to track moves and resizes
        root.bind("<Configure>", update_position) 
# Place List into Boxes in Second Window
        for index, number in enumerate(unique_numbers):
            row_num = index // 10
#            target_row = row_num
            col_num = index % 10
            print(f"Row Number: {row_num}")
            new_height = second_window.winfo_reqheight() + 25            
            second_window.geometry(f"{second_window_width}x{new_height}")
            second_window.update_idletasks()
            entry_box2 = tk.Entry(second_window, width=5, font=('Arial', 14), bg="#4CAF50",fg="white", justify='center')    
        # Precise positioning on a row-by-row basis
            entry_box2.grid(row=row_num, column=col_num,padx=2, pady=2)                 
        # Place the unique number into the box
            entry_box2.insert(0, str(number))
            entry_box2.config(state="readonly", readonlybackground="#4CAF50")

    except ValueError:
        messagebox.showerror("Input Error", "Please enter valid integers.")

# Results Output Label
label_result = tk.Label(
    root, text="Your Numbers Will Appear Here!", font=("Arial", 12, "bold"), fg="#333333")
label_result.grid(row=6, column=0, padx=25, pady=1, sticky="w")

# Generates Random Numbers Button
btn_1 = tk.Button(root, padx = 18, text='Generate', font=("Arial", 12, "bold"), command = generate_unique_numbers,
    bg="#4CAF50",
    fg="white",)
btn_1.place(x=250, y=10)

# Clears In/Out Fields
def reset_fields():
# Resets Main Window Input Fields
    entry_count.delete(0, tk.END)
    entry_start.delete(0, tk.END)
    entry_end.delete(0, tk.END)
    label_result.config(text="Your Numbers Will Appear Here!", font=("Arial", 12, "bold"), fg="#333333")
# 1ms delay, to Close Window 2
    second_window.after(100, second_window.destroy)

# Reset Button
btn_2 = tk.Button(root, padx = 30, text='Reset', font=("Arial", 12, "bold"), command = reset_fields, 
    bg="#f3a72f",
    fg="black",)
btn_2.place(x=250, y=50)

# Reset Button
btn_3 = tk.Button(root, padx = 22, text='Exit', width=1, font=("Arial", 12, "bold"), command = root.destroy, 
    bg="#FFDF20",
    fg="black",)
btn_3.place(x=300, y=100)


# Keep root open
root.mainloop()