Skip to main content
`Ctrl`+`K`

# Spinner

The `Gtk.Spinner` displays an icon-size spinning animation. It is often used as an alternative to a `Gtk.ProgressBar` for displaying indefinite activity, instead of actual progress.

To start the animation, use `Gtk.Spinner.start()`, to stop it use `Gtk.Spinner.stop()`.

## Example

     1import gi
     2
     3gi.require_version("Gtk", "4.0")
     4from gi.repository import Gtk
     5
     6
     7class SpinnerAnimation(Gtk.ApplicationWindow):
     8    def __init__(self, **kargs):
     9        super().__init__(**kargs, title="Spinner Demo")
    10
    11        button = Gtk.ToggleButton(label="Start Spinning")
    12        button.connect("toggled", self.on_button_toggled)
    13        button.props.active = False
    14
    15        self.spinner = Gtk.Spinner()
    16
    17        box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, homogeneous=True)
    18        box.append(button)
    19        box.append(self.spinner)
    20        self.set_child(box)
    21
    22    def on_button_toggled(self, button):
    23        if button.props.active:
    24            self.spinner.start()
    25            button.set_label("Stop Spinning")
    26
    27        else:
    28            self.spinner.stop()
    29            button.set_label("Start Spinning")
    30
    31
    32def on_activate(app):
    33    win = SpinnerAnimation(application=app)
    34    win.present()
    35
    36
    37app = Gtk.Application(application_id="com.example.App")
    38app.connect("activate", on_activate)
    39
    40app.run(None)

## Extended example

An extended example that uses a timeout function to start and stop the spinning animation. The `on_timeout()` function is called at regular intervals until it returns `False`, at which point the timeout is automatically destroyed and the function will not be called again.

### Example

     1import gi
     2
     3gi.require_version("Gtk", "4.0")
     4from gi.repository import Gtk, GLib
     5
     6
     7class SpinnerAnimation(Gtk.ApplicationWindow):
     8    def __init__(self, **kargs):
     9        super().__init__(**kargs, title="Spinner Demo")
    10
    11        main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
    12        self.set_child(main_box)
    13
    14        self.spinner = Gtk.Spinner()
    15        main_box.append(self.spinner)
    16
    17        self.label = Gtk.Label()
    18        main_box.append(self.label)
    19
    20        self.entry = Gtk.Entry()
    21        self.entry.props.text = "10"
    22        main_box.append(self.entry)
    23
    24        self.button_start = Gtk.Button(label="Start timer")
    25        self.button_start.connect("clicked", self.on_button_start_clicked)
    26        main_box.append(self.button_start)
    27
    28        self.button_stop = Gtk.Button(label="Stop timer")
    29        self.button_stop.props.sensitive = False
    30        self.button_stop.connect("clicked", self.on_button_stop_clicked)
    31        main_box.append(self.button_stop)
    32
    33        self.timeout_id = None
    34        self.connect("unrealize", self.on_window_destroy)
    35
    36    def on_button_start_clicked(self, _widget):
    37        """Handles 'clicked' event of button_start."""
    38        self.start_timer()
    39
    40    def on_button_stop_clicked(self, _widget):
    41        """Handles 'clicked' event of button_stop."""
    42        self.stop_timer("Stopped from button")
    43
    44    def on_window_destroy(self, _widget):
    45        """Handles unrealize event of main window."""
    46        # Ensure the timeout function is stopped
    47        if self.timeout_id:
    48            GLib.source_remove(self.timeout_id)
    49            self.timeout_id = None
    50
    51    def on_timeout(self):
    52        """A timeout function.
    53        Return True to stop it.
    54        This is not a precise timer since next timeout
    55        is recalculated based on the current time.
    56        """
    57        self.counter -= 1
    58        if self.counter <= 0:
    59            self.stop_timer("Reached time out")
    60            return False
    61        self.label.props.label = f"Remaining: {int(self.counter / 4)!s}"
    62        return True
    63
    64    def start_timer(self):
    65        """Start the timer."""
    66        self.button_start.props.sensitive = False
    67        self.button_stop.props.sensitive = True
    68        # time out will check every 250 milliseconds (1/4 of a second)
    69        self.counter = 4 * int(self.entry.props.text)
    70        self.label.props.label = f"Remaining: {int(self.counter / 4)!s}"
    71        self.spinner.start()
    72        self.timeout_id = GLib.timeout_add(250, self.on_timeout)
    73
    74    def stop_timer(self, label_text):
    75        """Stop the timer."""
    76        if self.timeout_id:
    77            GLib.source_remove(self.timeout_id)
    78            self.timeout_id = None
    79        self.spinner.stop()
    80        self.button_start.props.sensitive = True
    81        self.button_stop.props.sensitive = False
    82        self.label.props.label = label_text
    83
    84
    85def on_activate(app):
    86    win = SpinnerAnimation(application=app)
    87    win.present()
    88
    89
    90app = Gtk.Application(application_id="com.example.App")
    91app.connect("activate", on_activate)
    92
    93app.run(None)