2

It makes a while that I've been trying to put a drawing area on a scrolled window. I've been reading articles about pygtk and C solutions but I think that they are not working in pyGobject.

I made a minimal example:

from gi.repository import Gtk, Gdk
import cairo

class Test(Gtk.Window):

    def __init__(self):
        Gtk.Window.__init__(self)
        sw=Gtk.ScrolledWindow()
        vp=Gtk.Viewport()
        box=Gtk.VBox()

        vp.set_size_request(100,100)

        for i in range(3):
            da=Gtk.DrawingArea()
            da.connect("draw", self.draw, [0.3, 0.4, 0.6], da)
            da.set_size_request(100,100)
            box.add(da)

        sw.add(vp)
        vp.add(box)        
        self.add(sw)
        self.show_all()

    def draw(self, widget, event, color, da):
        cr = widget.get_property('window').cairo_create()
        cr.rectangle(0, 0, 100, 100)
        cr.set_source_rgb(color[0], color[1], color[2])
        cr.fill()

main=Test()
Gtk.main()

So the problem is that the drawing areas are not always rendered. This is for example, a gtk2 working code:

import gtk, cairo

class Test(gtk.Window):

    def __init__(self):
        gtk.Window.__init__(self)
        sw=gtk.ScrolledWindow()
        vp=gtk.Viewport()
        box=gtk.VBox()

        for i in range(3):
            da=gtk.DrawingArea()
            da.connect("expose-event", self.draw, [0.3, 0.4, 0.6], da)
            box.add(da)

        sw.add(vp)
        vp.add(box)        
        self.add(sw)
        self.show_all()

    def draw(self, widget, event, color, da):
        cr = widget.get_property('window').cairo_create()
        cr.rectangle(0, 0, 100, 100)
        cr.set_source_rgb(color[0], color[1], color[2])
        cr.fill()

main=Test()
gtk.main()

Please do not point me to the following articles, I've already read them multiple times!

I've added the viewport and a size_request, what else could be missing?

Thanks for the help!

user6039980
  • 3,108
  • 8
  • 31
  • 57

2 Answers2

2

by Emmanuele over the Gtk mailing list:

from gi.repository import Gtk, Gdk
import cairo

class Test(Gtk.Window):

    def __init__(self):
        Gtk.Window.__init__(self)
        sw=Gtk.ScrolledWindow()
        vp=Gtk.Viewport()
        box=Gtk.VBox()

        vp.set_size_request(100,100)

        for i in range(3):
            da=Gtk.DrawingArea()
            da.connect("draw", self.draw, [0.3, 0.4, 0.6])
            da.set_size_request(100,100)
            box.add(da)

        sw.add(vp)
        vp.add(box)        
        self.add(sw)
        self.show_all()

    def draw(self, widget, cr, color):
        cr.rectangle(0, 0, 100, 100)
        cr.set_source_rgb(color[0], color[1], color[2])
        cr.fill()
        cr.queue_draw_area(0, 0, 100, 100)

        return True

main=Test()
Gtk.main()

You should read the API reference for GTK+ 3.x:

https://developer.gnome.org/gtk/stable

as well as the Python API reference:

http://lazka.github.io/pgi-docs/#Gtk-3.0

0

You can add a damage region and force the redraw, I've slightly modified you example (sorry I could not resist fixing a couple of things) and add the queue_draw_area

I would strongly suggest avoid using a Gtk.DrawingArea and using a canvas widget instead, drawing on a canvas it's just much easier, GooCanvas is a good example but there are many others that you can use.

from gi.repository import Gtk, Gdk
import math, cairo

class Test(Gtk.Window):

    def __init__(self):
        Gtk.Window.__init__(self)
        sw=Gtk.ScrolledWindow()
        box=Gtk.VBox()

        for i in range(3):
            da=Gtk.DrawingArea()
            da.connect("draw", self.draw, [0.3, 0.4, 0.6], da)
            da.set_size_request(100,100)
            box.pack_start(da, True, True, 10)

        sw.add(box)
        self.add(sw)

        self.connect("destroy", Gtk.main_quit)
        self.show_all()

    def draw(self, widget, event, color, da):
        cr = widget.get_property('window').cairo_create()
        lg1 = cairo.LinearGradient(0.0, 0.0, 100, 0)
        lg1.add_color_stop_rgb(0, color[0], color[1], color[2])
        lg1.add_color_stop_rgb(1, color[0], color[1], color[2])
        cr.rectangle(0, 0, 100, 100)
        cr.set_source(lg1)
        cr.fill()
        da.queue_draw_area(0, 0, 100, 100)

main=Test()
Gtk.main()
gianmt
  • 1,162
  • 8
  • 15
  • Hi gianmt, do not worry for the modifications that was just a minimal example. I executed your code and I still having the same problems. Did you tested your code? The problem is when the scrolled window is active (with both bars). I'm over gtk 3.12 –  May 02 '15 at 20:13
  • Hi rsm, I did test it, gtk 3.16 though – gianmt May 02 '15 at 20:26
  • ah :/, that may be the reason. I'll let the post open in case some one find a solution, over 3.14. gtk 3.16 it is far from being in Debian :/ –  May 02 '15 at 22:39
  • previously when I said i was in 3.12 I made a mistake, Debian jessie is over 3.14 –  May 02 '15 at 22:42
  • @rms I was testing it on a gtk 3.16 on windows, now I just tested it on a gtk 3.14 (gtk3-3.14.12-1.fc21.x86_64 - Fedora on a WM) and it works, I'm starting to wonder if i understood your problem... – gianmt May 03 '15 at 19:19
  • Yeah, I actually think that you didnt ! or maybe its my debian/gtk buggign. Take a look to this [image](http://i62.tinypic.com/hsngc9.jpg). As you can see, when the scroll bars are active the drawing area is not correctly rendered. You must resize the window until you don't need the bars to correctly render the window! –  May 03 '15 at 20:53
  • I've added an answer In case you want to look at it. And by the way, you were right about the queue ! thanks for helping :) –  May 06 '15 at 12:00