'Refresh A Widget/Grid in GTK3 python every second

So this is my first GTK3 python app, and what I am trying to do is display the track art, song name, and artist of my currently playing Spotify song.

This works, but I need it to refresh every few seconds so the app will switch the song info.

This is my code so far:

import gi
import os
import subprocess
import urllib.request as ur
from PIL import Image

gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib, GdkPixbuf
if os.path.exists("art.png"):
    os.remove("art.png")
else:
    print("")

class Window(Gtk.Window):
    def __init__(self):
        super().__init__(title="current song playing")
        artist = subprocess.Popen("playerctl metadata artist", shell=True, stdout=subprocess.PIPE).communicate()[0]
        artist = artist.strip().decode('ascii')

        print(Gtk.events_pending())

        song   = subprocess.Popen("playerctl metadata title", shell=True, stdout=subprocess.PIPE).communicate()[0]
        song   = song.strip().decode('ascii')

        art    = subprocess.Popen("playerctl metadata mpris:artUrl", shell=True, stdout=subprocess.PIPE).communicate()[0]
        art    = art.strip().decode('ascii')

        ur.urlretrieve(art, "art.png")
        pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(
        filename="art.png",
        width=200,
        height=200,
        preserve_aspect_ratio=True)
        self.image = Gtk.Image.new_from_pixbuf(pixbuf)

        self.main_box = Gtk.Box()
        self.label = Gtk.Label()
        self.label.set_markup("<big>%s - %s</big>\n" % (artist, song))
        self.label.set_justify(Gtk.Justification.CENTER)

        self.label.set_hexpand(True)
        self.image.set_hexpand(True)
        self.label.set_vexpand(True)
        self.image.set_vexpand(True)

        grid = Gtk.Grid()
        grid.add(self.image)
        grid.attach_next_to(self.label, self.image, Gtk.PositionType.BOTTOM, 1, 2)

        self.main_box.pack_start(self.image, True, True, 0)
        self.main_box.pack_start(self.label, True, True, 0)

        self.add(grid)
        self.show_all()

def main():
    win=Window()
    win.show()
    win.connect("destroy", Gtk.main_quit)
    Gtk.main()

if __name__ == "__main__":
    main()

If tried different methods of doing this, and looking at the docs, neither have worked/helped.



Solution 1:[1]

gtk4 drawing-model

There are multiple ways to drive the clock, at the lowest level you can request a particular phase with gdk_frame_clock_request_phase() which will schedule a clock beat as needed so that it eventually reaches the requested phase. However, in practice most things happen at higher levels:

  • If you are doing an animation, you can use gtk_widget_add_tick_callback() which will cause a regular beating of the clock with a callback in the Update phase until you stop the tick.
  • If some state changes that causes the size of your widget to change you call gtk_widget_queue_resize() which will request a Layout phase and mark your widget as needing relayout.
  • If some state changes so you need to redraw some area of your widget you use the normal gtk_widget_queue_draw() set of functions. These will request a Paint phase and mark the region as needing redraw.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 anthony lutjen