Creating a widget that uses cairo

In preparation for creating a pie chart widget, I wrote the following program to draw a circle. It seems to work fine, but I am wondering whether I got it right as I am using cairo for the first time. The code seems too simple.

import cairo
import math

import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk

class Circle(Gtk.DrawingArea):
    def __init__(self, parent):
        super().__init__()
        self.set_size_request(200, 200)

        self.connect('draw', self.on_draw)

    def on_draw(self, circle, context):
        alloc = self.get_allocation()
        size = min(alloc.width, alloc.height)

        context.translate(size / 2.0, size / 2.0)
        context.scale(size / 2.0, size / 2.0)

        context.set_source_rgb(1.0, 0.0, 0.0)
        context.arc(0.0, 0.0, 0.5, 0.0, math.pi * 2.0)
        context.fill()

        return False

def main():
    win = Gtk.Window()
    win.connect('destroy', lambda w: Gtk.main_quit())

    vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
    label = Gtk.Label.new('Circle widget')
    circle = Circle(win)

    vbox.pack_start(label, False, 0, 0)
    vbox.pack_start(circle, True, True, 0)

    win.add(vbox)
    win.show_all()

    Gtk.main()

if __name__ == '__main__':
    main()

You are not using the parent argument of Circle.__init__ for anything. So, maybe you should remove it altogether.

Everything else seems good enough. Although, I do have some more suggestions.

  • If you are writing a new app, you should probably be using GTK4 instead of GTK3. Here is a demo for reference.
  • Even if you decide to use GTK3, it is recommended to use Gtk.Application class.

Thanks for your reply. And thanks for the demo program.

parent was left over from when I thought I needed get_style_context so that I could invoke cairo_set_source_rgba. I have also seen render_background in sample code. Apparently, I do not need these instructions. I never fully understood what they do, which is a big part of the reason I wondered whether my widget was “too simple”. I am content in my ignorance if I truly do not need those statements, but I wanted to be sure that omitting them would not cause obscure problems downstream when I incorporate my pie-chart widget in my application.

I have been haunted by the Gtk4 question. I thought I would wait until Gtk4 was included in the Ubuntu distribution by default (I am using 22.04), but your encouragement has gotten me reconsidering. It appears that packages are available in the repository for Gtk4 and for GStreamer, which I also need.

If you set a background using CSS then you would need to use render_background to see it. Without it, the CSS background will be ignored and the background will always be transparent.

You can also simplify more by removing self.connect('draw', self.on_draw) and changing the method to this:

    def do_draw(self, context):

In pygobject, methods prefixed with do_ will automatically get used as the vfunc for that signal, so there is no need to connect them.

I installed GTK4 and I was able to run your demo program. However, I then discovered that Glade does not support GTK4. I have many Glade files in my application. I could redo the entire GUI specification using Cambalache or in code, but either solution would be onerous. Moreover, Cambalache is at version 0.10.3, which suggests that it might lack features I will need. gtk4-builder-tool simplify --3to4 can convert Glade files, but I see reports that it does not always work. In any case, having to convert Glade files after every tweak would be inconvenient. I think the best solution might be to wait until my application is nearly done and then use gtk4-builder-tool once on each Glade file. The lack of a GUI designer is a serious impediment to GTK4 adoption.

There is a GUI designer, it is Cambalache. Glade currently is not being updated and there are many fundamental issues with it that make it not a good choice for GTK3: Glade Not Recommended – Chris's Design & Development