Search code examples
pythontkintercustomtkinter

Collapse labels if empty


I have three labels that are directly under eachother (see image). I'd like the labels to be collapsed when they're empty.

In the case of the image, the second label is empty. I'd like the third label to be placed on the location of the second label.

In WPF (.NET) this would be done via:

<Style TargetType="TextBlock">
        <Style.Triggers>
            <Trigger Property="Text" Value="">
                <Setter Property="Visibility" Value="Collapsed" />
            </Trigger>
        </Style.Triggers>
</Style>

The simplified code of the picture below is as such:

import customtkinter as ctk

gui = ctk.CTk()

status = ctk.StringVar(value="status_test")
warning = ctk.StringVar(value="")
error = ctk.StringVar(value="error_test")

ctk.CTkLabel(gui, textvariable=status, text_color="grey", wraplength=gui.winfo_vrootwidth()).pack()
ctk.CTkLabel(gui, textvariable=warning, text_color="yellow", wraplength=gui.winfo_vrootwidth()).pack()
ctk.CTkLabel(gui, textvariable=error, text_color="red", wraplength=gui.winfo_vrootwidth()).pack()

gui.mainloop()

Image of UI


Solution

  • The normal way to do this is to is to call pack_forget when the label is empty, given that you're using pack.

    This requires that you separate the creation of the labels from the layout of the labels so that you can reference them individually.

    Here's an example:

    import customtkinter as ctk
    
    gui = ctk.CTk()
    
    status = ctk.StringVar(value="status_test")
    warning = ctk.StringVar(value="warning_test")
    error = ctk.StringVar(value="error_test")
    
    status_label = ctk.CTkLabel(gui, textvariable=status, text_color="grey", wraplength=gui.winfo_vrootwidth())
    warning_label = ctk.CTkLabel(gui, textvariable=warning, text_color="yellow", wraplength=gui.winfo_vrootwidth())
    error_label = ctk.CTkLabel(gui, textvariable=error, text_color="red", wraplength=gui.winfo_vrootwidth())
    
    status_label.pack()
    warning_label.pack()
    error_label.pack()
    
    
    def add_warning(message):
        if message == "":
            warning_label.pack_forget()
        else:
            warning_label.pack(after=status_label)
            warning.set(message)
    
    b1 = ctk.CTkButton(gui, text="Add warning", command=lambda: add_warning("Warning!"))
    b2 = ctk.CTkButton(gui, text="Remove warning", command=lambda: add_warning(""))
    b1.pack(side="bottom")
    b2.pack(side="bottom")
    
    gui.mainloop()