如何使用Gtk Sharp和C#创建用于绘制代码的Cairo Context

时间:2017-12-06 14:48:11

标签: c# mono gtk cairo gtk#

我有几个按钮和一个我想画一些东西的区域。我一直试图用Cairo创建一个绘图表面,因为Gtk的Drawing Area小部件似乎不知道如何绘制基本形状(或者我只是没有找到它是如何做到的)。

我找到了一些关于此的基本教程(例如:http://zetcode.com/gui/gtksharp/drawing/http://www.mono-project.com/docs/tools+libraries/libraries/Mono.Cairo/tutorial/),但无法弄清楚如何在我的应用中制作绘图表面,以及按钮和标签,而不仅仅是一个仅用于开罗绘画的新空白窗口。

这就是我的应用现在所寻找的方式:

enter image description here

所以,我希望中间的空白部分是我的绘图区域。

我尝试了这个,我认为应该使我的应用程序中的绘图区域小部件可以与开罗一起绘制:

enter image description here

我不太明白我应该在这做什么。

我只需要绘制一些基本的圆圈和线条,这样我就不需要开罗,任何有关如何使用Gtk绘图的帮助#将非常感激!

3 个答案:

答案 0 :(得分:2)

你走在正确的轨道上。不幸的是,GTK#和Cairo有一些怪癖。首先,我强烈建议使用EventBox小部件而不是DrawingArea。与直觉相反,我从来没有太多运气让DrawingArea正常工作。 EventBox的工作方式大致相同,只是通过将VisibleWindow设置为false可以使背景透明。

public class YourWidget : EventBox
{
    public YourWidget() {
        Visible = true;
        VisibleWindow = false;
        ExposeEvent += OnExpose;
    }
}

接下来,在事件框中绘图时使用的纵坐标是基于父窗口的原点,即整个应用程序窗口。每个窗口小部件对象都包含一些属性Allocation,这些属性指定它在父窗口中的位置以及它的大小。为了在自定义窗口小部件窗口的范围内绘制,您必须引用这些点。这仅适用于扩展EventBox小部件的自定义小部件。如果内存服务,则使用DrawingArea的小部件是小部件位置的引用。最后,我将在using块中包含开罗上下文,这样您就不会忘记丢弃该对象。

protected void OnExpose(object sender, ExposeEventArgs args) {
    using (Context cr = Gdk.CairoHelper.Create(this.GdkWindow)) {
          int top = Allocation.Top;
          int left = Allocation.Left;  

          cr.Rectangle(left + 8, top + 8, 10, 10);
          cr.SetSourceRGB(255, 0, 0);
          cr.Fill();
    }
}

此外,自从我开始使用新的GTK#应用程序以来,它已经有一段时间了,但您可能需要将Mono.Cairo包添加到项目的引用中。最后,我使用了基于EventBox的小部件来创建several custom widgets for a touch application,它们也可以作为一个参考来帮助您入门。我希望这一切都有所帮助。

答案 1 :(得分:2)

我可以在这里添加一些内容。你可以使用DrawingArea,我从来没有像Skyler那样遇到过同样的麻烦,但是开罗几乎可以使用任何小部件或基本窗口。我使用了DrawingAreas,我还扩展了基本小部件,并使用cairo进行渲染。

我可以给出的关键指标:

  • 使用窗口小部件的Expose事件来获取Cairo需要绘制的GdkWindow的引用。例如:

    protected void OnExpose (object o, Gtk.ExposeEventArgs args)
    {
        Draw (args.Event.Window);
    }
    
  • 在绘图操作中,使用Cairo Helper创建开罗上下文。

    private void Draw (Gdk.Window w)
    {
        double _bg = (55.0 / 255.0);
        using (Cairo.Context _c = Gdk.CairoHelper.Create (w)) {
            _c.LineWidth = 2;
            _c.SetSourceRGB (_bg, _bg, _bg);
            _c.Rectangle (0, 0, this.WidthRequest, this.HeightRequest);
            _c.StrokePreserve ();
            _c.SetSourceRGBA (_bg, _bg, _bg, 0.5);
            _c.Fill ();
            _c.Dispose ();
        }
    }
    
  • 最后使用Dispose(),否则会遇到内存问题。

如果您愿意,我还可以向您展示如何使用Pango文本渲染库。它们比在cairo库中使用SetText()操作更复杂但要好得多。

干杯,M

答案 2 :(得分:1)

您可以在没有 Cairo 的情况下进行绘制,但这被认为是过时的,至少使用C#。

最全面的信息(不过很多)可以在这里找到: http://www.mono-project.com/docs/tools+libraries/libraries/Mono.Cairo/

就个人而言,正如#muszeo所提到的,我使用了自定义的 DrawingArea

public class MyWidget: Gtk.DrawingArea {       
    public MyWidget(int width, int height)
    {
        this.Width = width;
        this.Height = height;
        this.SetSizeRequest( width, height );
        this.ExposeEvent += (o, args)  => this.OnExposeDrawingArea();
    }

    /// <summary>
    /// Redraws the widget
    /// </summary>
    private void OnExposeDrawingArea()
    {
        using (var canvas = Gdk.CairoHelper.Create( this.GdkWindow ))
        {
            // Draw with the canvas
            // /* i.e. */ canvas.LineTo( 100, 100 );
            canvas.Stroke();

            // Clean
            canvas.GetTarget().Dispose();
        }
    }
}

然后你只需要在一个窗口中创建你的小部件(也许是一个对话框?):

var dlg = new Gtk.Dialog( "Demo", this, Gtk.DialogFlags.Modal );
var swScroll = new Gtk.ScrolledWindow();

MyWidget widget = new MyWidget( 512, 512 );
swScroll.AddWithViewport( widget );
dlg.VBox.PackStart( swScroll, true, true, 5 );
dlg.AddButton( Gtk.Stock.Close, Gtk.ResponseType.Close );
dlg.ShowAll();
dlg.Run(); 

我使用各种Gtk#simple demoes保存一个repo,其中一个是使用Cairo来绘制图形的非常基本的Chart类:

http://github.com/baltasarq/GtkSharpDemo

希望这有帮助。