如何使用 Gtk Sharp 和 C# 创建用于在代码中绘图的 Cairo Context
How to create Cairo Context for drawing in code with Gtk Sharp and C#
我有几个按钮和一个区域,我想在其中绘制一些东西。我一直在尝试创建一个用 Cairo 绘图的表面,因为 Gtk 的 Drawing Area
小部件似乎不知道如何绘制基本形状(或者我只是找不到它是如何绘制的)。
我找到了一些关于此的基本教程(例如:http://zetcode.com/gui/gtksharp/drawing/ or http://www.mono-project.com/docs/tools+libraries/libraries/Mono.Cairo/tutorial/)但无法弄清楚如何在我的应用程序中制作用于绘图的表面,以及按钮和标签,而不仅仅是一个新的空白window 仅用于开罗绘图。
这是我的应用程序现在的样子:
所以,我想把中间的空白部分作为我的绘图区。
我尝试了这个,我认为它应该使我的应用程序中的绘图区小部件可以使用 Cairo 绘制:
我不太明白我应该在这里做什么。
我只需要在上面画一些基本的圆和线,所以我真的不需要 Cairo,如果能帮助我用 Gtk# 画画,我将不胜感激!
你走在正确的轨道上。不幸的是,GTK# 和 Cairo 有一些怪癖。首先,我强烈建议使用 EventBox 小部件而不是 DrawingArea。与直觉相反,我从来没有运气让 DrawingArea 正常工作。 EventBox 的工作方式大致相同,只是您可以通过将 VisibleWindow 设置为 false 来使背景透明。
public class YourWidget : EventBox
{
public YourWidget() {
Visible = true;
VisibleWindow = false;
ExposeEvent += OnExpose;
}
}
接下来,在事件框中绘制时使用的坐标基于父window的原点,即整个应用程序window。每个小部件对象都包含一些属性 Allocation
,这些属性指定它在父对象 window 中的位置以及它的大小。为了在自定义小部件 window 的范围内绘制,您必须参考这些点。这仅适用于扩展 EventBox 小部件的自定义小部件。如果没记错的话,使用 DrawingArea 的小部件是从小部件位置引用的。最后,我会将 Cairo 上下文包含在 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,它也可以作为帮助您入门的参考。希望对大家有所帮助。
我可以在这里添加一些内容。您可以使用 DrawingArea,我从来没有遇到过像 Skyler 一样的麻烦,但 Cairo 几乎可以在任何小部件或基础 window 上绘制。我经常使用 DrawingAreas,我还扩展了基本小部件并使用 cairo 进行渲染。
我能给的关键点:
使用小部件的 Expose 事件获取对 Cairo 需要绘制到的 GdkWindow 的引用。例如:
protected void OnExpose (object o, Gtk.ExposeEventArgs args)
{
Draw (args.Event.Window);
}
在您的绘图操作中,使用 Cairo Helper 创建一个 Cairo 上下文。
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
您可以在没有 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();
}
}
}
那么您只需要在 window(也许是对话框?)中创建您的小部件:
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# 简单演示的 repo,其中之一是使用 Cairo 绘制图形的非常基本的图表 class:
http://github.com/baltasarq/GtkSharpDemo
希望对您有所帮助。
我有几个按钮和一个区域,我想在其中绘制一些东西。我一直在尝试创建一个用 Cairo 绘图的表面,因为 Gtk 的 Drawing Area
小部件似乎不知道如何绘制基本形状(或者我只是找不到它是如何绘制的)。
我找到了一些关于此的基本教程(例如:http://zetcode.com/gui/gtksharp/drawing/ or http://www.mono-project.com/docs/tools+libraries/libraries/Mono.Cairo/tutorial/)但无法弄清楚如何在我的应用程序中制作用于绘图的表面,以及按钮和标签,而不仅仅是一个新的空白window 仅用于开罗绘图。
这是我的应用程序现在的样子:
所以,我想把中间的空白部分作为我的绘图区。
我尝试了这个,我认为它应该使我的应用程序中的绘图区小部件可以使用 Cairo 绘制:
我不太明白我应该在这里做什么。
我只需要在上面画一些基本的圆和线,所以我真的不需要 Cairo,如果能帮助我用 Gtk# 画画,我将不胜感激!
你走在正确的轨道上。不幸的是,GTK# 和 Cairo 有一些怪癖。首先,我强烈建议使用 EventBox 小部件而不是 DrawingArea。与直觉相反,我从来没有运气让 DrawingArea 正常工作。 EventBox 的工作方式大致相同,只是您可以通过将 VisibleWindow 设置为 false 来使背景透明。
public class YourWidget : EventBox
{
public YourWidget() {
Visible = true;
VisibleWindow = false;
ExposeEvent += OnExpose;
}
}
接下来,在事件框中绘制时使用的坐标基于父window的原点,即整个应用程序window。每个小部件对象都包含一些属性 Allocation
,这些属性指定它在父对象 window 中的位置以及它的大小。为了在自定义小部件 window 的范围内绘制,您必须参考这些点。这仅适用于扩展 EventBox 小部件的自定义小部件。如果没记错的话,使用 DrawingArea 的小部件是从小部件位置引用的。最后,我会将 Cairo 上下文包含在 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,它也可以作为帮助您入门的参考。希望对大家有所帮助。
我可以在这里添加一些内容。您可以使用 DrawingArea,我从来没有遇到过像 Skyler 一样的麻烦,但 Cairo 几乎可以在任何小部件或基础 window 上绘制。我经常使用 DrawingAreas,我还扩展了基本小部件并使用 cairo 进行渲染。
我能给的关键点:
使用小部件的 Expose 事件获取对 Cairo 需要绘制到的 GdkWindow 的引用。例如:
protected void OnExpose (object o, Gtk.ExposeEventArgs args) { Draw (args.Event.Window); }
在您的绘图操作中,使用 Cairo Helper 创建一个 Cairo 上下文。
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
您可以在没有 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();
}
}
}
那么您只需要在 window(也许是对话框?)中创建您的小部件:
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# 简单演示的 repo,其中之一是使用 Cairo 绘制图形的非常基本的图表 class:
http://github.com/baltasarq/GtkSharpDemo
希望对您有所帮助。