Clutter学习(四):带有滚动条的Stage Widget

来源:互联网 发布:网络投票公司 编辑:程序博客网 时间:2024/04/28 08:13

  我们知道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相关博客