首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

用 Guile 来为 GTK+ 应用添加扩展语言 Scheme(2)

用 Guile 来为 GTK+ 应用添加扩展语言 Scheme(2)

应用的创建如果您熟悉GTK+开发的话,创建上面的图形窗口是一件轻松的事。关键是创建Drawarea控件,定义指针area,则area->window即指向area控件底层的GdkWindow,我们应用GDK中的gdk_draw_*系列函数就可以在此控件的GdkWindow上绘图并能正常显示出来。
同时我们还应当将此area复制一个pixmap指针用于保存文件,也就是说在向屏幕绘制图形的同时还要向pixmap绘图(不可见),保存时只保存此pixmap中的图像就可以了,这样做虽然很笨拙,但可以实现,其它方法(如直接保存area的内容为图像)笔者尚未实现。GTK+中的GDK-PIXBUF库提供了保存图像功能,我们这里简单的利用了一下,用gdk_pixbuf_get_from_drawable函数取得pixmap的pixbuf,然后用gdk_pixbuf_save函数将取得的pixbuf保存为文件,可以选择多种图像格式,为了简便我们只用PNG格式保存,这样我们的应用就更具实用价值了。
我们设定画板的默认尺寸为600x400,在绘图区上自动形成一个以左上角为原点(0,0)高为 400 像素宽为 600 像素的平面直角坐标系,以此为基点,我们就可以用 gdk_draw_* 系列函数在画板上绘图了。
以下为 gdk_draw_* 系列函数以及此应用涉及的其它相关函数的简单介绍(更详细的信息见参考资料):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
                       //画点函数
void gdk_draw_point (GdkDrawable *drawable, GdkGC *gc, gint x, gint y);
//画线函数
void gdk_draw_line (GdkDrawable *drawable, GdkGC *gc,
                    gint x1_, gint y1_, gint x2_, gint y2_);
//画矩形函数
void gdk_draw_rectangle (GdkDrawable *drawable, GdkGC *gc, gboolean filled,
                         gint x, gint y, gint width, gint height);
//画弧线函数
void gdk_draw_arc (GdkDrawable *drawable, GdkGC *gc, gboolean filled,
                   gint x, gint y, gint width, gint height, gint angle1, gint angle2);
//绘制字符串函数
void gdk_draw_layout (GdkDrawable *drawable, GdkGC *gc,
                      gint x, gint y, PangoLayout *layout);
//画多边形函数
void gdk_draw_polygon (GdkDrawable *drawable, GdkGC *gc, gboolean filled,
                       GdkPoint *points, gint npoints);




这些函数中都包括GdkDrawable *drawable和GdkGC *gc这两个参数,它们分别代表我们的绘图板和绘图的前景颜色;
在gdk_draw_rectangle、gdk_draw_arc和gdk_draw_polygon函数中还有一个gboolean filled参数,用来指定是否添充颜色,如为TRUE则添充颜色,如为FALSE则不添充颜色。
需要说明的是在gdk_draw_arc函数的最后是两个关于角度的参数,其中angle1表示此弧线旋转的角度,参数angle2表示此弧线的角度,此函数将圆周分为360度后,又将其中的1度64等分,也就是说,angle2为1的话,表示此弧线只有六十四分之一度;而angle1为1的话,则表示将此弧线旋转六十四分之一度。
gdk_draw_polygon函数中的GdkPoint结构如下所示:
1
2
3
4
struct GdkPoint {
  gint x;
  gint y;
};




正好用Scheme语言中的点对来处理,car对应x,cdr对应y,而gdk_draw_polygon需要的GdkPoint数组指针正好用列表来实现。
gdk_draw_layout来向绘图板输出字符串,其中的PangoLayout *layout参数表示要输出的字符串,可以用gtk_widget_create_pango_layout函数创建。
另外我们还用到void gdk_gc_set_rgb_fg_color(GdkGc *gc, GdkColor *color);函数,用来设置绘画板的前景颜色,这个函数用到了GdkColor结构,此结构中用red, green, blue三个整型值来表示RGB颜色值,如此我们可以用RGB规则轻松设定颜色。
还有很多其它绘图及相关函数,此应用并未涉及,有兴趣的读者可以试一试。关于应用中控件的构建和组织可以见参考资料中的文章,此处不做更多的说明。
Guile中的C API当了解了上面的绘图功能后,下一个课题就是Guile了。在Guile中,Scheme语言的每个R5RS中定义的基础过程几乎都有一个C函数与之相对应,也就是说,每一条Scheme语句都是在执行一个或多个C函数。如 Scheme 语言过程 string? 事实上就是在运行scm_string_p 函数,而 string->list 过程则是在运行 scm_string_to_list 函数。要调用 Guile 开发库的 C API,只需要在我们的代码中加入 #include <libguile.h> 就可以了。另一个重要的功能是初始化Guile的动态链接库以调用Guile的各种功能,只要在代码中执行scm_init_guile函数即可实现。
下面我们编写C代码来调用Guile中的C API,以此达到运行简单的Scheme语句的目的,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//tt.c
#include <libguile.h>
int main(int argc, char *argv[])
{
        char *ver = "(display \"Guile version \")(display (version))";
        char *newline = "(newline)";
        char *lambda = "(define newdisplay (lambda (n) (display n) (display \"\t\")))";
        char *call = "(for-each newdisplay '(Tom Bob Peter Jim Lucy))";
        scm_init_guile();
        scm_c_eval_string(ver);
        scm_c_eval_string(newline);
        scm_c_eval_string(lambda);
        scm_c_eval_string(call);
        scm_c_eval_string(newline);
        return 0;
}
//the end




再做一个简单的Makefile来实现make编译,内容如下:
1
2
3
4
5
6
        CC = gcc
CFLAGS = `guile-config compile`
LIBS = `guile-config link`
all:
        $(CC) $(CFLAGS) -c tt.c
        $(CC) $(LIBS) tt.o -o tt




编译后,执行./tt程序,结果如下所示:
1
2
Guile version 1.6.4
Tom     Bob     Peter   Jim     Lucy




可见我们完全可以用C语言来实现自己的Scheme语言代码的运行,其中包括Scheme语言中的变量、过程的定义和调用。此处只用到了scm_c_eval_string函数,实事上几乎所有的Guile的C API可以像它这样来调用。
如果我们逆向思考,我们就可以自己定义一个C函数,通过某种功能将其转换为新的Scheme过程,再运行这个新定义的Scheme过程,就是执行我们自己定义的新的C函数。事实的确如此!
返回列表