pythontkinter

Tkinter Python - Update a label from an instance method goes to segmentation fault


I'm trying to update a Label with a method that is called via a scheduler process, but when i try to configure the label, the app crashes with a segmentation fault

This is my script

class Gui():
    def __init__(self):
        app = Tk()
        self.initialize_user_interface()

    def initialize_user_interface(self):
        self.title("Title")
        self.geometry(f"{1100}x{700}")

        self.sidebar_frame = Frame(self)
        self.sidebar_frame.grid()
        self.my_label = Label(self.sidebar_frame)
        self.my_label.grid()
        thread = threading.Thread(target=self.start_schedule, daemon=True)
        thread.start()

    def start_schedule(self):
        schedule.every(30).seconds.do(lambda: self.update_label())

    def update_label(self):
        self.my_label=configure(text="Custom Text")


if __name__ == "__main__":
    app = Gui()
    app.mainloop()

I tried to call the method inside the class, using the self but i keep getting the error of segmentation fault


Solution

  • Here's a working example that updates the text of the Label widget to a random number every 3 seconds. It demonstrates how to handle this using tkinter's after method rather than relying on threading and other modules.

    I've also fixed the issue preventing the Frame and Label from appearing by passing them both to pack(), and I fixed the typo in self.my_label.configure

    from tkinter import *
    from random import randint  # for demonstration purposes
    
    
    class Gui(Tk):  # inherit from Tk in your main app class
        def __init__(self) -> None:
            super().__init__()  # initialize Tk (your inherited superclass)
            self.initialize_user_interface()
            self.update_label()  # begin label updates
            # if you'd rather start the label updates after a delay, do this instead:
            # self.after(30_000, self.update_label)
            # you can set whatever delay you like here
    
        def initialize_user_interface(self) -> None:
            self.title("Title")
            self.geometry(f"{1100}x{700}")
    
            self.sidebar_frame = Frame(self)
            self.sidebar_frame.pack()
            self.my_label = Label(self.sidebar_frame)
            self.my_label.pack()
    
        def update_label(self) -> None:
            """Set the label to a random value for demonstration"""
            self.my_label.configure(text=randint(0, 100))
            # repeat this function after however many mS
            self.after(3000, self.update_label)
    
    
    if __name__ == "__main__":
        app = Gui()
        app.mainloop()
    

    As an aside, you generally want to avoid "star" imports, like from tkinter import * because they can lead to a problem called "namespace pollution" (think about what would happen if some other module you were using also had a class named Label). Typically, you'll see import tkinter as tk, and any related classes are then instantiated with tk as a prefix like tk.Label, tk.Button, etc.