amrsa
amrsa

Reputation: 245

tk.Toplevel window that comes up in wrong place

I'm trying to define a popup window with a combobox, which does something in the parent window.
It's more or less done (perhaps not the best way...), except that the popup window wouldn't come up in the right place: it would always show in the upper-left corner, even if the main window was elsewhere.
I suppose this behavior is to be expected from Toplevel windows.

Now, in order to make it show centralized with the main window and with the right size, I used geometry method on the popup window.
But for this to work, I have to apply the update method, so that the size of the window is known.
That gives me the popup window in the right place and with the correct dimensions.
However, another problem arises: the window shows up, in the upper-left corner, for a fraction of a second, before it shows in the right place.
This is certainly because the call of update is before the positioning and resizing.

Here's the code.

import tkinter as tk
from tkinter import ttk

class PopupCombobox():

    def __init__(self, p_app, values):
        self.master = p_app.root
        self.parent = p_app
        self.gui = tk.Toplevel(self.master)
        # Drop the maximize button, and prevent to resize the window
        self.gui.resizable(width=tk.FALSE, height=tk.FALSE)
        self.gui.wait_visibility()
        self.gui.grab_set()
        self.gui.title("Pop up")
        self.gui.combo = ttk.Combobox(self.gui, values=values, width=15, state='readonly')
        self.gui.combo.grid(column=0, row=0, padx=8, pady=4)
        # self.gui.withdraw()
        self.gui.update()
        # self.gui.iconify()
        # self.gui.deiconify()
        self.centralize_widget()
        self.gui.combo.bind("<<ComboboxSelected>>", self.callback)

    def callback(self, event):
        self.parent.e.configure(text=self.gui.combo.get())
        self.gui.destroy()

    def centralize_widget(self):
        # (x,y) is the root upper-left corner
        x = self.master.winfo_x()
        y = self.master.winfo_y()
        # The width and height of the root
        w_master = self.master.winfo_width()
        h_master = self.master.winfo_height()
        # The width and height of the widget
        w = self.gui.winfo_width()
        h = self.gui.winfo_height()
        self.gui.geometry("%dx%d+%d+%d" % (w, h, x + (w_master - w)/2, y + (h_master - h)/2))


class App:

    def __init__(self, root):
        self.root = root
        self.root.geometry("300x100+450+300")
        self.e = ttk.Label(root, text="text")
        self.e.grid()
        self.b = ttk.Button(root, text="Pop it up!", command=self.do_it)
        self.b.grid()
        self.choice = None

    def do_it(self):
        PopupCombobox(self, values=('a', 'b', 'c', 'd'))


win = tk.Tk()
app = App(win)
win.mainloop()

I tried with the commented methods withdraw before update and iconify or deiconify after.
With deiconify the observed behavior is exactly the same; with iconify the program blocks.

There must be a better way. Any ideas?

Thanks in advance.

Upvotes: 1

Views: 201

Answers (1)

Thingamabobs
Thingamabobs

Reputation: 8072

I can't reproduce your problem on my computer. It seems like it depends on system speed. But a solution can be:

self.gui.attributes('-alpha', 0) #makes window invisible
self.gui.update_idletaks() #get true values
self.gui.after_idle(lambda : self.gui.attributes('-alpha', 1)) #makes window visble again

Upvotes: 1

Related Questions