[cairo] What is the c# code to draw an image as a background then draw other stuff over it?

Maarten Bosmans mkbosmans at gmail.com
Sun Nov 15 09:14:37 PST 2009


2009/11/14 alan battersby <alan.battersby at ntlworld.com>:
> Maarten,
> Thanks for the advice, I followed your suggestions and all works fine.
> The problem I had with freezing seems to have gone away.
>
> I have another slight problem. I am using a transformation between the
> profile coordinates and the mouse coordinates. This depends on the
> drawing area size, the max grid radius and a possible translation (as I
> can pan across the grid).
>
> During editing I pick up the mouse coordinates, and then want to use the
> contexts inverse transformation to get the actual values. However as the
> context is not an argument passed to the motion notify event this means
> I have to save the context in my class to be used within the notify
> event handler instead of having it inside a using block.

A context is not supposed to be a long lived object, so you should
store a context in a member variable. Just create it from the surface
in every event handler that needs a context. That should be cheap
enough to do.

You could handle the coordinate transform yourself, as it seems that
your just translating, so that is quite simple. Another option is to
save the mouse coordinates and doing all the calculations with them
from the ExposeEventHandler, but that may not be appropriate for your
application.

> However I keep getting the following message.
>
> Cairo.Context: called from finalization thread, programmer is missing a
> call to Dispose
>
> My question is where and how do I call the Dispose function and what is
> its name.

The C# bindings for Cairo aren't really good at garbage-collecting the
context and surface resources. So you'll have to manually free the
memory when you don't need it anymore. You can do that with
((IDisposable) context).Dispose() and surface.Destroy().

Use these calls at the end of an EventHandler for local variabels and
don't forget to properly dispose a surface when you overwrite a member
variable with a new value. If you do this properly, you don't get the
warning message anymore and your app won't leak surface resources
anymore.

> I did this because I thought that to keep getting a context, scaling it
> etc just to use the inverse transformation would be inefficient.

As I said above, it isn't. But as always, first profile your
application to see where the performance bottlenecks are and then try
to work around them.

> Thanks
>
> Alan
>
> CODE
>
> void DrawProfile()
> {
>
>    if (_grid == null)
>        drawGridToSurface();
>
>    ct = Gdk.CairoHelper.Create (this.GdkWindow);  *** would normally have
> using ( ... ) here
>
>    // draw grid as background
>    ct.SetSource(_grid);
>    ct.Paint();
>    scaleView(ct);
>    drawOutline(ct,outlineColr);
>    if (_editingstarted) {
>        ct.Save();
>        ct.Color = editingColr;
>        ct.MoveTo(0,0);
>        double lw = 1.0, lh=1.0 , ld=10.0;
>        ct.InverseTransformDistance(ref lw,ref lh);
>        ct.LineWidth = Math.Min(lw,lh);
>        Vector3 mp = posn.Vector3;
>        ct.LineTo(mp.X ,mp.Y);
>        ct.TextPath("Radius: " + posn.Radius.ToString());
>        string a = "Angle: " + posn.Angle.ToString();
>        TextExtents xa = ct.TextExtents(a);
>        ct.MoveTo(mp.X,mp.Y - 2 * xa.Height);
>        ct.TextPath(a);
>        ct.Stroke();
>        ct.Restore();
>    }
>
> }
>
> void HandleMotionNotifyEvent (object o, MotionNotifyEventArgs args)
> {
>    if (_translateflag) {
>        translateVector = new PointD(args.Event.X - startmove.X,
>                                 args.Event.Y - startmove.Y);
>    _grid = null;
>    }
>    if (_editingstarted) {
>        // userPosition needs the cairo context
>        posn.Vector3 = userPosition(args.Event.X, args.Event.Y);
>        _profile.UpdateValues(_editAngle,posn);
>        _editAngle = posn.Angle;
>    }
>
>    if (_translateflag || _editingstarted)
>        QueueDraw();
>    }
> }
>
>
> Vector3 userPosition(double xp, double yp)
> {
>    double x = xp;
>    double y = yp;
>    ct.InverseTransformPoint(ref x, ref y);
>    return new Vector3((float)x,(float)y,0);
> }
>
>
> void scaleView(Context ct)
> {
>    int width =0;
>    int height=0;
>    float maxr = _maxGridRadius + _radialscale;
>    GdkWindow.GetSize(out width,out height);
>    ct.Translate(width/2, height/2);
>    ct.Translate(translateVector.X,translateVector.Y);
>    double scale = currentscalefactor * Math.Min(width/(2 * maxr),height/(2
> * maxr));
>    ct.Scale(scale,scale);
> }
>
>
>


More information about the cairo mailing list