我们知道Moblin在v2 beta版本开始使用clutter来制作UI。Clutter作为UI受到了越来越多OSV的关注,虽然我个人觉得Clutter对显卡驱动的依赖,以及通用的显卡驱动vesa并不能很好的支持,但是Clutter确实提供了绚丽的动态效果,而且和GTK、QT等相互兼容,这使得我们不会为选择Clutter而过多考虑对系统的影响,例如是否影响其他的linux应用,openoffice,firefox等等,至少可以保守地选择在GTK的容器里面加入Clutter的stage widget。
下面的小例子的学习资料来源: http://www.openismus.com/documents/clutter_tutorial/0.9/docs/tutorial/html/actor-scrolling.html ,but we did a litte more。因为我并不是GTK的开发者,所以会在一些GTK上面多做一些实验。实际上我一般尽量避免参与界面的开发,除了JAVA的一些控制台软件的开发,当然还有一个VC,不过是利用工具在那里摆来摆去。
这是个查看图片的小例子,能够通过滚动条查看不在显示区域的图片,因此我们需要一个尺寸大的图片文件来配合实验。对于需要通过滚动条来解决有限可视空间,在GTK中我们可以采用GtkScrolledWindow
,但是这种方式无法在GtkClutterEmbed中使用,因为Clutter从显示硬件获取,而不通过GTK+的绘图系统(drawing system),这个同时也可以解析为什么在vesa的驱动下,clutter反应就像慢动作一样。这是需要使用GtkClutterViewPort,它并不提供自动加载滚动条,需要使用GtkAdjustment使用GtkSrcollbar widget。
这些图形界面开发感觉就是一个容器套另一个容器。我们先解析一下下面例子的布局。我们在这个例子中重温如何在GTK容器中放入Clutter小部件。
我们创建一个gtk的windows部件,然后加入我们的布局部件table(2×2),上次例子使用的是vbox的竖直摆放方式。图片放在(0,0)区域,水平滚动条和竖直滚动条分别放置在(0,1)和(1,0)区域。(1,1)区域不摆放任何小部件。
我们使用Clutter来显示图片。在GTK容器中加入Clutter,我们需要先在所需布局的位置加入一个ClutterWidget,表示这里将使用Clutter容器,任何Clutter都需要ClutterStage,因此我们从该ClutterWidget获得一个embed stage。剩下的操作就是标准的Clutter的操作。为了显示图片,我们需要使用Viewport,然后将突破texture(从指定的文件路径获取的图片)放置在显示区内。
我们在这个例子中,增加了一个检测到窗口大小发生改变的时候,从新调整图片的适应情况的回调函数。
#include <clutter/clutter.h>
#include <clutter-gtk/clutter-gtk.h>
#include <stdlib.h>ClutterActor * viewport = NULL;
/* 部件大小改变的触发函数:根据部件(stage)的实际大小,重新适配viewport的大小*/
static gboolean on_win_resize(ClutterStage * widget, ClutterEvent * event,gpointer user_data){
float w = 0, h = 0;
ClutterActor * stage = (ClutterActor *) user_data;
clutter_actor_get_size(stage, &w, &h);
printf("[Configure-event]: stage size is %.0f * %.0f, reset viewport./n", w,h);
clutter_actor_set_size (viewport, (int) w, (int) h);
return TRUE;
}int main(int argc, char * argv[]){
ClutterColor stage_color = { 0x61, 0x64, 0x8c, 0xff};/** g_error会中断应用(abort the app)因此,我们不需要在后面加上exit(-1),
* 同时我们在使用g_error的时候需要谨慎,是否真的要结束进程。 */
if(argc != 2)
g_error("Usage : stage_scroll <image file>");
if(gtk_clutter_init(&argc,&argv) != CLUTTER_INIT_SUCCESS)
g_error("Unable to init gtk-clutter");/** 创建GTK window作为主窗口主容器,同时提供关闭窗口就结束应用的处理 */
GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size (GTK_WINDOW (window), 640, 480);
g_signal_connect(window,"destroy",G_CALLBACK(gtk_main_quit),NULL);/** 在GTK windows的容器中放入布局GtkTable ,并将table置为显示模式。 */
GtkWidget * table = gtk_table_new (2, 2, FALSE);
gtk_container_add (GTK_CONTAINER (window), table);
gtk_widget_show(table);/* 将clutter嵌入widget放入table(0,0)位置,将stage放入widget之中,作为clutter的容器 */
GtkWidget * clutter_widget = gtk_clutter_embed_new ();
gtk_table_attach (GTK_TABLE(table), clutter_widget, 0, 1, 0, 1,
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_show (clutter_widget);
ClutterActor * stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED(clutter_widget));
clutter_stage_set_color ( CLUTTER_STAGE(stage), & stage_color);
clutter_actor_set_size ( stage, 640, 480 );
clutter_actor_show(stage);/* 创建一个viewport的ClutterActor放入stage容器,允许scroll.
* By passing NULL it will create new GtkAdjustments. The viewport will contian the image.
* gtk_clutter_viewport_new add third param z_adjust in version 0.10 */
viewport = gtk_clutter_viewport_new (NULL, NULL,NULL);
clutter_container_add_actor( CLUTTER_CONTAINER(stage),viewport);/** Put an Image in viewport . */
ClutterActor *texture = clutter_texture_new_from_file (argv[1], NULL);
if(texture == NULL){
g_print("[ERROR] : The file is not existed!/n");
exit(-1);
}
/* texture将自动从0,0开始在viewport中摆放,无须再设置postition,也不起作用。*/
clutter_container_add_actor (CLUTTER_CONTAINER (viewport), texture);
//clutter_actor_set_position (texture, 0, 0);
float w = 0, h = 0;
clutter_actor_get_size(viewport, &w, &h);
printf("[INFO]: viewport size is %.0f * %.0f./n",w,h);
clutter_actor_get_size(stage, &w, &h);
printf("[INFO]: stage size is %.0f * %.0f./n",w,h);
/* 我们增加了GTK大小的事件检测,无需在这里进行自动适配图片的大小(使得滚动条有效工作),在回调函数中进行*/
//clutter_actor_set_size (viewport, 640, 480);/* Create scrollbars and connect them to viewport: */
GtkAdjustment *h_adjustment = NULL;
GtkAdjustment *v_adjustment = NULL;
gtk_clutter_scrollable_get_adjustments (GTK_CLUTTER_SCROLLABLE(viewport),
&h_adjustment, &v_adjustment);
GtkWidget *scrollbar = gtk_vscrollbar_new (v_adjustment);
gtk_table_attach (GTK_TABLE (table), scrollbar,1,2,0,1,0,GTK_EXPAND | GTK_FILL,0,0);
gtk_widget_show (scrollbar);
scrollbar = gtk_hscrollbar_new (h_adjustment);
gtk_table_attach (GTK_TABLE (table), scrollbar,0,1,1,2,GTK_EXPAND | GTK_FILL,0,0,0);
gtk_widget_show (scrollbar);/* configure_event:这个事件会在我们改变部件(widget)大小时产生,包括窗口创建时。*/
g_signal_connect(clutter_widget,"configure_event", G_CALLBACK(on_win_resize),stage);
gtk_widget_show(GTK_WIDGET(window));
gtk_main();
return EXIT_SUCCESS;
}
gtk组件的行为或X服务器发送的事件可以和下列事件联系起来。具体可以在Gtk+2.0的著名文档中查看。
button_press_event //按钮按下
button_release_event //按钮释放
motion_notify_event //鼠标移动
delete_event //使用窗口管理器关闭
destroy_event //关闭
expose_event //曝光
key_press_event //按键按下
key_release_event //按键释放
enter_notify_event //鼠标指针进入组件
leave_notify_event //鼠标指针离开组件
configure_event //属性改变
focus_in_event //获得聚焦
focus_out_event //失去聚焦
map_event //映射
unmap_event //消失
property_notify_event //属性改变
selection_clear_event //选择清除
selection_request_event //选择请求
selection_notify_event //选择通知
proximity_in_event //接近
proximity_out_event //离开
drag_begin_event //拖开始
drag_request_event //拖请求
drag_end_event //拖结束
drop_enter_event //放进入
drop_leave_event //放离开
drop_data_available_event //放数据可用
相关链接:
我的Clutter相关博客