小小千想和您聊一聊

当前位置: 首页> 技术分享> GTK进阶学习:绘图事件二

GTK进阶学习:绘图事件二

  如果在窗口上绘图,要设置允许窗口绘图:

void gtk_widget_set_app_paintable(
GtkWidget *widget, 
gboolean app_paintable )
widget:控件指针
app_paintable:TRUE允许绘图,FALSE不允许


  绘图注意事项(能不用绘图尽量不用,绘图效率较低):

  1)尽量不要在绘图回调函数做太多的复杂数据处理,绘图的任务只是绘图,尽量不要做别的事情 (因为绘图随时有可能自动调用,导致效率很低)

void fun()
{
gtk_widget_queue_draw() // error
}


  2)绘图回调函数里一定不要调用gtk_widget_queue_draw() (因为会导致死循环,效率很低)

  绘图流程:

  1)允许窗口能绘图(顺序随意)

  2)连接曝光信号"expose-event"

  3)实现绘图回调函数(绘图是绘窗口里面的window成员,在GtkWidget这个结构体里能找到这个成员 )

  以下例子为,通过绘图实现背景,按按钮窗口的笑脸会移动:

  源码代码:

#include <cairo.h>	// 绘图所需要的头文件
#include <gtk/gtk.h>
 
int startx = 0;
int w = 400;
int h = 300;
 
// 绘图事件
gboolean on_expose_event (GtkWidget * widget, GdkEventExpose *event, gpointer data)
{
	cairo_t *cr = gdk_cairo_create(widget->window);	// 创建cairo环境,注意参数
 
	// 画背景图
	// 获取图片
	GdkPixbuf *src_pixbuf = gdk_pixbuf_new_from_file("./image/back.jpg", NULL); 
	// 指定图片大小
	GdkPixbuf* dst_pixbuf = gdk_pixbuf_scale_simple(src_pixbuf, w, h, GDK_INTERP_BILINEAR);
	
	// dst_pixbuf作为cr环境的画图原材料,(0, 0):画图的起点坐标
	gdk_cairo_set_source_pixbuf(cr, dst_pixbuf, 0, 0);
	cairo_paint(cr);	// 绘图
	
	// 释放资源
	g_object_unref(dst_pixbuf);
	g_object_unref(src_pixbuf);
 
	// 画笑脸
	src_pixbuf = gdk_pixbuf_new_from_file("./image/face.png", NULL);
	dst_pixbuf = gdk_pixbuf_scale_simple(src_pixbuf, 80, 80, GDK_INTERP_BILINEAR);
	gdk_cairo_set_source_pixbuf(cr, dst_pixbuf, startx, (h/10)*3);
	cairo_paint(cr);
	g_object_unref(dst_pixbuf);
	g_object_unref(src_pixbuf);
 
	/*
	// 绘图与写字共存的测试
	// 如果绘完图片后想继续写字或画线,
	// 必须手动设置画笔颜色cairo_set_source_rgb()
	// 否则,字体或线条会被图片覆盖。
	cairo_set_source_rgb(cr, 0.627, 0, 0);  // 设置字体颜色
	cairo_set_font_size(cr, 40.0);			// 设置字体大小
	cairo_move_to(cr, 50.0, 130.0);			// 写字的起点坐标
	cairo_show_text(cr, "This is a test");	// 写字
	*/
 
	cairo_destroy(cr);	// 回收所有Cairo环境所占用的内存资源
 
	return FALSE;	// 必须返回FALSE
}
 
// 按钮按下回调函数
void deal_button_clicked(GtkWidget *widget, gpointer data)
{
	startx += 20;
	if(startx >= w){
		startx = 0;
	}
 
	gtk_widget_queue_draw( GTK_WIDGET(data) );	// 更新刷图区域,刷新整个窗口
}
 
int main (int argc, char *argv[])
{
	gtk_init (&argc, &argv);
 
	GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL); // 顶层窗口
	g_signal_connect(window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
	gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);	// 中央位置显示
	gtk_widget_set_size_request(window, 400, 300);		    // 窗口最小大小
	gtk_window_set_resizable(GTK_WINDOW(window), FALSE);	// 固定窗口的大小
 
	GtkWidget *table = gtk_table_new(5, 5, TRUE);	// 表格布局容器
	gtk_container_add(GTK_CONTAINER(window), table); // 容器加入窗口
 
	// button
	GtkWidget *button = gtk_button_new_with_label("click me");		// 按钮
	g_signal_connect(button, "clicked", G_CALLBACK(deal_button_clicked), window);
	gtk_table_attach_defaults(GTK_TABLE(table), button, 3, 4, 4, 5);// 把按钮加入布局
 
	// 绘图事件信号与回调函数的连接
	g_signal_connect(window, "expose-event", G_CALLBACK(on_expose_event), NULL);
 
	gtk_widget_set_app_paintable(window, TRUE);	// 允许窗口可以绘图
 
	gtk_widget_show_all(window);	// 显示所有控件
 
	gtk_main();
	
	return 0;
}


  运行结果:

上一篇:HTML5工具初识之网页编辑器

下一篇:GTK进阶学习:绘图事件一

QQ技术交流群

千锋物联网官方①群
858310440

加入群聊