如何使用 Cairo 和 Gtk3 在 GtkDrawingArea 中绘制一条线
Posted
技术标签:
【中文标题】如何使用 Cairo 和 Gtk3 在 GtkDrawingArea 中绘制一条线【英文标题】:How to draw a line in a GtkDrawingArea using Cairo with Gtk3 【发布时间】:2012-01-19 19:55:58 【问题描述】:有人可以向我展示一个使用 C 语言在 Cairo 和 Gtk3 中绘制 GtkDrawingArea
中的一条线的最小工作示例。我试图在 Gtk3 测试文件夹中修改testcairo.c
,但我无法让它工作。请不要在开罗网站上推荐教程; Zetcode.com 或 gnome.org,它们要么不适用于 Gtk3,要么不是最小的工作示例。
【问题讨论】:
【参考方案1】:我明白了。关键区别在于,对于 gtk+3,您必须从“绘制”信号处理程序中进行绘制。使用 gtk+2 它来自“expose-event”信号处理程序。这是minimal working example。
【讨论】:
这很有帮助。我想提一下,如果您使用的是“draw”信号,ZetCode.com 上的教程现在已经是最新的了。 这个链接现在每次点击它都会导致一个随机的广告客户,就好像这个域已经丢失了一样。我搜索了标题,但没有找到任何东西。答案的核心信息有效,但演示丢失。 @cardiffspaceman 我从网络档案中找到了它,这是少数几个可能比Stack Overflow 更长寿的网站之一。不过,您必须向下滚动两页才能找到任何代码。【参考方案2】:这是一个完整的工作示例:
确保已安装 gtk3-devel
(在 Fedora #dnf install gtk3-devel 中)
在 Ubuntu 中:sudo apt install libgtk-3-dev
编译:gcc draw.c `pkg-config --cflags gtk+-3.0 --libs gtk+-3.0` -o draw
#include <gtk/gtk.h>
gboolean draw_callback (GtkWidget *widget, cairo_t *cr, gpointer data)
guint width, height;
GdkRGBA color;
GtkStyleContext *context;
context = gtk_widget_get_style_context (widget);
width = gtk_widget_get_allocated_width (widget);
height = gtk_widget_get_allocated_height (widget);
gtk_render_background(context, cr, 0, 0, width, height);
cairo_arc (cr, width/2.0, height/2.0, MIN (width, height) / 2.0, 0, 2 * G_PI);
gtk_style_context_get_color (context, gtk_style_context_get_state (context), &color);
gdk_cairo_set_source_rgba (cr, &color);
gdk_cairo_set_source_rgba (cr, &color);
cairo_fill (cr);
return FALSE;
gint main(int argc,char *argv[])
GtkWidget *window, *drawing_area;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
drawing_area = gtk_drawing_area_new();
gtk_container_add (GTK_CONTAINER (window), drawing_area);
gtk_widget_set_size_request (drawing_area, 200, 100);
g_signal_connect (G_OBJECT (drawing_area), "draw", G_CALLBACK (draw_callback), NULL);
gtk_widget_show_all (window);
gtk_main ();
return 0;
【讨论】:
【参考方案3】:任何人都在 2020 年这样做。这是重构为使用 GTK3 的 Zetcode 示例,它绘制了您想要的内容,因此线条不会奇怪地连接。我添加了 cmets 来解释发生了什么。
/* To compile: gcc linetest.c -o linetest `pkg-config --cflags --libs gtk+-3.0`
* C program for basic drawing with GTK+ and cairo.
* Working 2020 example if this got you stuck, http://zetcode.com/gfx/cairo/basicdrawing/
* Note: the above command line uses backticks (`), it's right before 1 on your keyboard.
*/
#include <cairo.h>
#include <gtk/gtk.h>
//function prototypes
static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr, gpointer user_data);
static void do_drawing(cairo_t *cr);
static gboolean clicked(GtkWidget *widget, GdkEventButton *event, gpointer user_data);
//end of function prototypes
/* Global variables for storing mouse coordinates,
* count is index of arrays, coordx and coordy are x and y coordinates of the mouse
*/
struct
int count;
double coordx[100];
double coordy[100];
glob;
/* Function: on_draw_event
*Parameters: GtkWidget, cairo_t, gpointer
*Use: This is the function we attach to the main method when we want to draw. It calls the do_drawing method.
*Example: g_signal_connect(G_OBJECT(darea), "draw", G_CALLBACK(on_draw_event), NULL);
*/
static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr, gpointer user_data)
do_drawing(cr);
return FALSE;
/* Function: do_drawing
*Parameters: cairo_t
*Use: It sets cairo canvas settings, and draws shapes with a for loop
*Settings: are commented
*Note: printf is used during debugging to find mouse click coordinates :)
*/
static void do_drawing(cairo_t *cr)
cairo_set_source_rgb(cr, 0, 0, 0);//Line colour
cairo_set_line_width(cr, 0.5);//Line width
if (glob.count > 1)
cairo_move_to(cr, glob.coordx[0], glob.coordy[0]);
//printf("from: x:%f, y:%f\n",glob.coordx[0],glob.coordy[0]);
//Connect lines.
for (int i = 1; i < glob.count; ++i)
cairo_line_to(cr, glob.coordx[i], glob.coordy[i]);
//printf("to: x:%f, y:%f\n",glob.coordx[i],glob.coordy[i]);
// Draw the above.
cairo_stroke(cr);
//resets array so shape can be drawn again.
glob.count = 0;
/* Function: clicked
*Parameters: GtkWidget, GdkEventButton, gpointer
*Use: Registers mouse clicks, 1 is right, 3 is left on laptop. Clicks may be 1, 2 or 3 on a desktop
*Note: printf is used during debugging to find mouse click coordinates :)
*/
static gboolean clicked(GtkWidget *widget, GdkEventButton *event,
gpointer user_data)
if (event->button == 1)
// printf("Right Click");
glob.coordx[glob.count] = event->x;
glob.coordy[glob.count++] = event->y;
// int i;
// for (i =0; i <= glob.count-1; i++)
// printf("%f\n", glob.coordx[i]);
//
if (event->button == 3)
//printf("left Click");
gtk_widget_queue_draw(widget);
return TRUE;
//Main method.
int main(int argc, char *argv[])
//widget variables, window and drawing area.
GtkWidget *window;
GtkWidget *darea;
//Set global count 0, so array is at beginning whenver program starts.
glob.count = 0;
//Always have this to start GTK.
gtk_init(&argc, &argv);
//Set new window, set new drawing area.
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
darea = gtk_drawing_area_new();
//Add the drawing area to the window.
gtk_container_add(GTK_CONTAINER(window), darea);
//You need this to register mouse clicks.
gtk_widget_add_events(window, GDK_BUTTON_PRESS_MASK);
//Attaching draw function to the main method.
g_signal_connect(G_OBJECT(darea), "draw",
G_CALLBACK(on_draw_event), NULL);
//You can close window when you exit button.
g_signal_connect(window, "destroy",
G_CALLBACK(gtk_main_quit), NULL);
//Register if left or right mouse click.
g_signal_connect(window, "button-press-event",
G_CALLBACK(clicked), NULL);
//Set window position, default size, and title.
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 400, 300);
gtk_window_set_title(GTK_WINDOW(window), "Lines");
//Show all widgets.
gtk_widget_show_all(window);
//start window
gtk_main();
return 0;
【讨论】:
您现在可以将它移植到 GTK4 ;) 这将很快发布。 .. GTK4 也会有 GTKSnapshot,并且不再使用 Cairo。【参考方案4】:// compila con valac --pkg gtk+-3.0 nombre_archivo.gs
uses
Gtk
Cairo
init
Gtk.init (ref args)
var TestCairo = new Ventana ()
TestCairo.show_all ()
Gtk.main ()
class Ventana : Window
area: Gtk.DrawingArea
init
title = "Test Genie + GTK + Cairo"
set_default_size (400, 400)
window_position = WindowPosition.CENTER
destroy.connect(Gtk.main_quit)
// área de dibujo
area: Gtk.DrawingArea = new Gtk.DrawingArea ()
// conecta el área de dibujo al método dibujar
area.draw.connect (dibujar)
// añade el área de dibujo a la ventana
add (area)
def dibujar (context : Context) : bool
context.set_source_rgba (1, 0, 0, 1)
context.set_line_width (2)
context.move_to (200, 100)
context.line_to (200, 300)
context.move_to (100, 200)
context.line_to (300, 200)
context.stroke ()
return true
更多 Genie + Gtk + Cairo 的例子在http://genie.webierta.skn1.com
【讨论】:
以上是关于如何使用 Cairo 和 Gtk3 在 GtkDrawingArea 中绘制一条线的主要内容,如果未能解决你的问题,请参考以下文章