[Python] Customtkinter: Close the dropdown menu when the dropdown arrow is clicked again

Discussão em 'Python' iniciado por Stack, Abril 25, 2025.

  1. Stack

    Stack Membro Participativo

    I have a piece CustomTkinter GUI that has several combobox dropdowns. I am having an issue with closing the popup when clicking the dropdown arrow for a second time. I have tried looking online for anybody having the same issue but I've not found much, and digging through the source code on GitHub didn't bring me any success either!

    I want these dropdowns to be able to close the popups when the dropdown arrow is clicked a second time. Currently when clicking it again the popup is recreated. The way to close the popup is to click anywhere else (i.e. selecting a dropdown option, clicking the accompanying entry box, or clicking anywhere outside of the combobox).

    Below is a dummy code/pseudo-code (as the toggle_dropdown method does not work) that attempts to solve my problem:

    import customtkinter as ctk


    class DummyApp(ctk.CTk):
    def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)

    self.geometry('200x100')

    self.combobox = ctk.CTkComboBox(self, values=['Option A', 'Option B'])
    self.combobox.pack(side='left')
    self.combobox.bind('<Button-1>', lambda event: self.toggle_dropdown(event, cbox=self.combobox))

    @staticmethod
    def toggle_dropdown(event, cbox: ctk.CTkComboBox):
    if cbox.cget('state') == 'shown':
    cbox.hide()
    else:
    cbox.show()


    if __name__ == '__main__':
    app = DummyApp()
    app.mainloop()


    I have tried to bind an event to my combobox such that when the dropdown arrow is clicked it will check if it is currently being displayed. If so: it closes the popup, and vice versa. This does not work because the event is being bound to the entry box rather than the dropdown arrow.

    So I would like two things fixed with this code:

    1. Bind the event to the dropdown arrow rather than the entry box (the lambda function would allow me to make the toggle_dropdown method generalisable to other comboboxes within my GUI)
    2. Fix toggle_dropdown to correctly check the 'shown/hidden' state, and then hide/show as appropriate.

    Thank you in advance for any assistance provided!

    EDIT:


    I could be wrong but it seems that this is a problem inherent to customtkinter. From testing this on other machines, with different versions of windows & customtkinter the problem still persists.

    I have opened an issue on the GitHub, so I hope it will be looked into: https://github.com/TomSchimansky/CustomTkinter/issues/2386

    I have temporarily created an inelegant solution whereby the CTKComboBox has been replaced with a CTkOptionMenu, as the self.optionbox.bind(...) applies to the entire widget. This has allowed me to change between 'normal/disabled' states, which correctly closes the dropdown menu on a second click.

    With this there was the problem after selecting an option of the widget having to be clicked twice in order to re-enable it, then select a new option. To solve this I have created a method dropdown_checker that re-enables the optionbox every 100 ms. See the below code:

    import customtkinter as ctk


    class DummyApp(ctk.CTk):
    def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)

    self.geometry('200x100')

    self.optionbox = ctk.CTkOptionMenu(self, values=['Option A', 'Option B'])
    self.optionbox.pack(side='left')
    self.optionbox.bind('<Button-1>', lambda event: self.toggle_dropdown(event, obox=self.optionbox))

    self.dropdown_checker()

    @staticmethod
    def toggle_dropdown(event, obox: ctk.CTkOptionMenu):
    if obox.cget('state') == 'normal':
    obox.configure(state='disabled')
    elif obox.cget('state') == 'disabled':
    obox.configure(state='normal')

    def dropdown_checker(self):
    self.optionbox.configure(state='normal')
    self.after(100, self.dropdown_checker)


    if __name__ == '__main__':
    app = DummyApp()
    app.mainloop()



    Like I said this is not a very good solution, but it is the only one I could think of whilst waiting for a reply to the GitHub issue. If anybody has any improvements/suggestions, I would love to hear them!

    Continue reading...

Compartilhe esta Página