使用 Cairo 绘制 GtkImage
Draw a GtkImage with Cairo
我尝试了类似笔记中提出的解决方案 (How to create a gtkimage from a cairo context, How do I create a gtkimage from a cairo surface)
但它们对我不起作用。
在我的实际程序中,后台任务计算物理模拟的连续状态,每次迭代都应在图表中添加一个点。如果我使用 GtkDrawingArea,我将不得不存储所有这些点(事先不知道会有多少),并在每个绘制信号上绘制所有内容。所以我的想法是使用 GtkImage,我必须在每次迭代中只绘制一个新点。
在下面的测试程序中,单击按钮时应该会绘制一些内容,但没有任何反应。有人可以指出错误吗?
/* Test for drawing an image with Cairo. To be compiled with:
gcc -Wall -g gtk_img.c -o gtk_img `pkg-config --cflags gtk+-3.0` `pkg-config --libs gtk+-3.0`
*/
#include <stdio.h>
#include <gdk/gdk.h>
#include <cairo.h>
#include <gtk/gtk.h>
#define BORDER 6
#define WIDTH 100
#define HEIGHT 100
cairo_surface_t *surf;
cairo_t *cr;
cairo_pattern_t *back, *fore;
/* Event Handlers
==============
*/
static gboolean Delete_Event
(GtkWidget *widget, GdkEvent *event, gpointer data)
{
return FALSE;
}
static void Destroy (GtkWidget *widget, gpointer data)
{
gtk_main_quit ();
}
static void Draw_Now (GtkWidget *widget, gpointer data)
{
printf("Draw button clicked\n");
cr = cairo_create (surf);
cairo_set_source (cr, back);
cairo_paint (cr);
cairo_set_source (cr, fore);
cairo_move_to (cr, 0.0, 0.0);
cairo_line_to (cr, 20.0, 20.0);
cairo_stroke (cr);
}
/* Main Program
============
*/
int main (int argc, char *argv[])
{
GtkWidget *window;
GtkImage *img;
GtkBox *vbox;
GtkButton *button;
// init GTK, make window with vbox
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (G_OBJECT (window), "delete_event",
G_CALLBACK (Delete_Event), NULL);
g_signal_connect (G_OBJECT (window), "destroy",
G_CALLBACK (Destroy), NULL);
gtk_container_set_border_width (GTK_CONTAINER (window), BORDER);
vbox = (GtkBox*)gtk_box_new (GTK_ORIENTATION_VERTICAL, BORDER);
gtk_container_add (GTK_CONTAINER(window), (GtkWidget*)vbox);
// make image
surf = cairo_image_surface_create (CAIRO_FORMAT_RGB24, WIDTH, HEIGHT);
img = (GtkImage*)gtk_image_new_from_surface (surf);
gtk_image_clear (img);
back = cairo_pattern_create_rgb (0.9, 0.9, 0.9);
fore = cairo_pattern_create_rgb (0.1, 0.1, 0.1);
gtk_box_pack_start (vbox, (GtkWidget*)img, TRUE, TRUE, FALSE);
// button
button = (GtkButton*)gtk_button_new_with_label ("Draw");
g_signal_connect
(G_OBJECT (button), "clicked", G_CALLBACK (Draw_Now), NULL);
gtk_box_pack_start (vbox, (GtkWidget*)button, FALSE, FALSE, FALSE);
// start GTK
gtk_widget_show_all (window);
gtk_main ();
return 0;
}
您正在绘制到 cairo 表面,但“什么都不知道”,因此不会触发重绘。
触发重绘的随机想法是调用 gtk_image_clear()
,然后调用 gtk_image_set_from_surface()
。我敢打赌有更好的方法可以做到这一点,但我真的不了解 GTK,抱歉。
我尝试了类似笔记中提出的解决方案 (How to create a gtkimage from a cairo context, How do I create a gtkimage from a cairo surface) 但它们对我不起作用。
在我的实际程序中,后台任务计算物理模拟的连续状态,每次迭代都应在图表中添加一个点。如果我使用 GtkDrawingArea,我将不得不存储所有这些点(事先不知道会有多少),并在每个绘制信号上绘制所有内容。所以我的想法是使用 GtkImage,我必须在每次迭代中只绘制一个新点。
在下面的测试程序中,单击按钮时应该会绘制一些内容,但没有任何反应。有人可以指出错误吗?
/* Test for drawing an image with Cairo. To be compiled with:
gcc -Wall -g gtk_img.c -o gtk_img `pkg-config --cflags gtk+-3.0` `pkg-config --libs gtk+-3.0`
*/
#include <stdio.h>
#include <gdk/gdk.h>
#include <cairo.h>
#include <gtk/gtk.h>
#define BORDER 6
#define WIDTH 100
#define HEIGHT 100
cairo_surface_t *surf;
cairo_t *cr;
cairo_pattern_t *back, *fore;
/* Event Handlers
==============
*/
static gboolean Delete_Event
(GtkWidget *widget, GdkEvent *event, gpointer data)
{
return FALSE;
}
static void Destroy (GtkWidget *widget, gpointer data)
{
gtk_main_quit ();
}
static void Draw_Now (GtkWidget *widget, gpointer data)
{
printf("Draw button clicked\n");
cr = cairo_create (surf);
cairo_set_source (cr, back);
cairo_paint (cr);
cairo_set_source (cr, fore);
cairo_move_to (cr, 0.0, 0.0);
cairo_line_to (cr, 20.0, 20.0);
cairo_stroke (cr);
}
/* Main Program
============
*/
int main (int argc, char *argv[])
{
GtkWidget *window;
GtkImage *img;
GtkBox *vbox;
GtkButton *button;
// init GTK, make window with vbox
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (G_OBJECT (window), "delete_event",
G_CALLBACK (Delete_Event), NULL);
g_signal_connect (G_OBJECT (window), "destroy",
G_CALLBACK (Destroy), NULL);
gtk_container_set_border_width (GTK_CONTAINER (window), BORDER);
vbox = (GtkBox*)gtk_box_new (GTK_ORIENTATION_VERTICAL, BORDER);
gtk_container_add (GTK_CONTAINER(window), (GtkWidget*)vbox);
// make image
surf = cairo_image_surface_create (CAIRO_FORMAT_RGB24, WIDTH, HEIGHT);
img = (GtkImage*)gtk_image_new_from_surface (surf);
gtk_image_clear (img);
back = cairo_pattern_create_rgb (0.9, 0.9, 0.9);
fore = cairo_pattern_create_rgb (0.1, 0.1, 0.1);
gtk_box_pack_start (vbox, (GtkWidget*)img, TRUE, TRUE, FALSE);
// button
button = (GtkButton*)gtk_button_new_with_label ("Draw");
g_signal_connect
(G_OBJECT (button), "clicked", G_CALLBACK (Draw_Now), NULL);
gtk_box_pack_start (vbox, (GtkWidget*)button, FALSE, FALSE, FALSE);
// start GTK
gtk_widget_show_all (window);
gtk_main ();
return 0;
}
您正在绘制到 cairo 表面,但“什么都不知道”,因此不会触发重绘。
触发重绘的随机想法是调用 gtk_image_clear()
,然后调用 gtk_image_set_from_surface()
。我敢打赌有更好的方法可以做到这一点,但我真的不了解 GTK,抱歉。