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

../../_images/spinner.png
 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

../../_images/spinner_ext.png
 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: {str(int(self.counter / 4))}'
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: {str(int(self.counter / 4))}'
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)