zoukankan      html  css  js  c++  java
  • gtk界面设计

    一。GTK基本

    #include <gtk/gtk.h>
    int main( int argc, char *argv[])
    {
        GtkWidget *window;
        /*初始化整个GTK+程序,是每一个GTK+程序必不可少的部分*/
        gtk_init(&argc, &argv);
        /*这里生成了一个窗口构件——GtkWindow,GTK_WINDOW_TOPLEVEL包含窗口的标题栏和边框,同意用窗口管理器来进行管理*/
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    
        /*开始显示窗口*/
        gtk_widget_show(window);
        gtk_main();
        return 0;
    }

    二。显示窗口和调整窗口

    #include <gtk/gtk.h>
    int main( int argc, char *argv[])
    {
        GtkWidget *window;
        /*初始化整个GTK+程序,是每一个GTK+程序必不可少的部分*/
        gtk_init(&argc, &argv);
        /*这里生成了一个窗口构件——GtkWindow,GTK_WINDOW_TOPLEVEL包含窗口的标题栏和边框,同意用窗口管理器来进行管理*/
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
        /*设置窗口标题*/
        gtk_window_set_title(GTK_WINDOW(window), "机器人");
        /*设置窗口默认大小*/
        gtk_window_set_default_size(GTK_WINDOW(window), 500, 400);
        /*
         * 设置窗口在显示器中的位置为居中。
         *   GTK_WIN_POS_NONE            :不固定
         *   GTK_WIN_POS_CENTER          : 居中
         *   GTK_WIN_POS_MOUSE           : 出现在鼠标位置
         *   GTK_WIN_POS_CENTER_ALWAYS   : 窗口改变大小的时候仍然居中
        */
        gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
    
        /*开始显示窗口*/
        gtk_widget_show(window);
        gtk_main();
        return 0;
    }

    三。设置应用程序的图标

    #include <gtk/gtk.h>
    
    
    GdkPixbuf *create_pixbuf(const gchar * filename)
    {
        GdkPixbuf *pixbuf;
        GError *error = NULL;
        /*
         * 函数gdk_pixbuf_new_from_file() 从一个图片文件中加载图象数据,从而生成一个新的 pixbuf,
         * 至于文件中包含图象的格式,是由系统自动检测的。如果该函数返回值是NULL 的话,程序就会出现错误。
        */
        pixbuf = gdk_pixbuf_new_from_file(filename, &error);
        if(!pixbuf) {
            fprintf(stderr, "%s
    ", error->message);
            g_error_free(error);
        }
        return pixbuf;
    }
    
    int main( int argc, char *argv[])
    {
        GtkWidget *window;
        /*初始化整个GTK+程序,是每一个GTK+程序必不可少的部分*/
        gtk_init(&argc, &argv);
        /*这里生成了一个窗口构件——GtkWindow,GTK_WINDOW_TOPLEVEL包含窗口的标题栏和边框,同意用窗口管理器来进行管理*/
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
        /*设置窗口标题*/
        gtk_window_set_title(GTK_WINDOW(window), "科希机器人-小希");
        /*设置窗口默认大小*/
        gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);
        /*
         * 设置窗口在显示器中的位置为居中。
         *   GTK_WIN_POS_NONE            :不固定
         *   GTK_WIN_POS_CENTER          : 居中
         *   GTK_WIN_POS_MOUSE           : 出现在鼠标位置
         *   GTK_WIN_POS_CENTER_ALWAYS   : 窗口改变大小的时候仍然居中
        */
        gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
    
        /*函数gtk_window_set_icon() 是为窗口设置图标用的,函数create_pixbuf是我们自定义的,目的是从一个图片中获取信息得到pixbuf。*/
        gtk_window_set_icon(GTK_WINDOW(window), create_pixbuf(argv[1]));
    
        /*开始显示窗口*/
        gtk_widget_show(window);
        gtk_main();
        return 0;
    }

    四。当点击关闭窗口(X)时,应该结束程序

      在命令行下运行这个demo,点击右上角的X时候,窗口虽然关闭了,但是程序还在运行,需要按ctrl+C(linux下 ctrl+D)来结束程序运行。我们希望点击X的时候就结束程序的运行。我们必须要明确为这个例子程序连接一个关闭的信号(destroy signal),然后调用回调函数gtk_main_quit() 实现结束程序。这里涉及到事件和信号会在日后讲到。

    #include <gtk/gtk.h>
    
    /*
      @Description: 从一个图片中获取信息得到pixbuf
      @param:       gchar filename
    */
    GdkPixbuf *create_pixbuf(const gchar * filename)
    {
        GdkPixbuf *pixbuf;
        GError *error = NULL;
        /*
         * 函数gdk_pixbuf_new_from_file() 从一个图片文件中加载图象数据,从而生成一个新的 pixbuf,
         * 至于文件中包含图象的格式,是由系统自动检测的。如果该函数返回值是NULL 的话,程序就会出现错误。
        */
        pixbuf = gdk_pixbuf_new_from_file(filename, &error);
        if(!pixbuf) {
            fprintf(stderr, "%s
    ", error->message);
            g_error_free(error);
        }
        return pixbuf;
    }
    
    int main( int argc, char *argv[])
    {
        GtkWidget *window;
        /*初始化整个GTK+程序,是每一个GTK+程序必不可少的部分*/
        gtk_init(&argc, &argv);
        /*这里生成了一个窗口构件——GtkWindow,GTK_WINDOW_TOPLEVEL包含窗口的标题栏和边框,同意用窗口管理器来进行管理*/
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
        /*设置窗口标题*/
        gtk_window_set_title(GTK_WINDOW(window), "机器人");
        /*设置窗口默认大小*/
        gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);
        /*
         * 设置窗口在显示器中的位置为居中。
         *   GTK_WIN_POS_NONE            :不固定
         *   GTK_WIN_POS_CENTER          : 居中
         *   GTK_WIN_POS_MOUSE           : 出现在鼠标位置
         *   GTK_WIN_POS_CENTER_ALWAYS   : 窗口改变大小的时候仍然居中
        */
        gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
    
        /*函数gtk_window_set_icon() 是为窗口设置图标用的,函数create_pixbuf是我们自定义的,目的是从一个图片中获取信息得到pixbuf。*/
        gtk_window_set_icon(GTK_WINDOW(window), create_pixbuf(argv[1]));
    
        /***********************************以下是信号处理部分************************************/
    
        /*关闭窗口时退出主循环*/
        g_signal_connect_swapped(G_OBJECT(window),"destroy",G_CALLBACK(gtk_main_quit), NULL);
    
        /***********************************以下是显示控件部分************************************/
        /*开始显示窗口*/
        gtk_widget_show(window);
    
        
        gtk_main();
        return 0;
    }

     五。添加简单菜单栏,以后在逐步完善

    #include <gtk/gtk.h>
    
    /*
      @Description: 从一个图片中获取信息得到pixbuf
      @param:       gchar filename
    */
    GdkPixbuf *create_pixbuf(const gchar * filename)
    {
        GdkPixbuf *pixbuf;
        GError *error = NULL;
        /*
         * 函数gdk_pixbuf_new_from_file() 从一个图片文件中加载图象数据,从而生成一个新的 pixbuf,
         * 至于文件中包含图象的格式,是由系统自动检测的。如果该函数返回值是NULL 的话,程序就会出现错误。
        */
        pixbuf = gdk_pixbuf_new_from_file(filename, &error);
        if(!pixbuf) {
            fprintf(stderr, "%s
    ", error->message);
            g_error_free(error);
        }
        return pixbuf;
    }
    
    
    int main( int argc, char *argv[])
    {
        GtkWidget *window;
        GtkWidget *vbox;            //盒装容器
        GtkWidget *menubar;         //菜单栏
        GtkWidget *menutoggle, *menu_tog_toggle,*menu_tog_toolbar, *menu_tog_statusbar;  //界面开关菜单
        //GtkWidget *menu_about, *menu_about_us;  //帮助菜单
    
        /*初始化整个GTK+程序,是每一个GTK+程序必不可少的部分*/
        gtk_init(&argc, &argv);
        /*这里生成了一个窗口构件——GtkWindow,GTK_WINDOW_TOPLEVEL包含窗口的标题栏和边框,同意用窗口管理器来进行管理*/
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
        /*设置窗口标题*/
        gtk_window_set_title(GTK_WINDOW(window), "小希机器人");
        /*设置窗口默认大小*/
        gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);
        /*
         * 设置窗口在显示器中的位置为居中。
         *   GTK_WIN_POS_NONE            :不固定
         *   GTK_WIN_POS_CENTER          : 居中
         *   GTK_WIN_POS_MOUSE           : 出现在鼠标位置
         *   GTK_WIN_POS_CENTER_ALWAYS   : 窗口改变大小的时候仍然居中
        */
        gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
    
        /*函数gtk_window_set_icon() 是为窗口设置图标用的,函数create_pixbuf是我们自定义的,目的是从一个图片中获取信息得到pixbuf。*/
        gtk_window_set_icon(GTK_WINDOW(window), create_pixbuf("/home/zxwbot/Pictures/1.jpg"));
    
        /*创建一个盒装容器并添加到窗口中*/
        vbox = gtk_vbox_new(FALSE, 0);
        gtk_container_add(GTK_CONTAINER(window), vbox);
    
        /*创建菜单*/
        menubar = gtk_menu_bar_new();   //代表整个菜单,是一个menu shell
    
        menutoggle = gtk_menu_new();   //这里代表第一列菜单toggle ,也是一个menu shell
        menu_tog_toggle = gtk_menu_item_new_with_label("导航");
        menu_tog_toolbar = gtk_menu_item_new_with_label("创建地图"); //toggle 菜单中子项
        menu_tog_statusbar = gtk_menu_item_new_with_label("清除地图");
    
        gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_tog_toggle), menutoggle);  //widget toggle菜单加入 menutoggle menu shell
        gtk_menu_shell_append(GTK_MENU_SHELL(menutoggle), menu_tog_toolbar);
        gtk_menu_shell_append(GTK_MENU_SHELL(menutoggle), menu_tog_statusbar);
    
        gtk_menu_shell_append(GTK_MENU_SHELL(menubar), menu_tog_toggle);
    
    
        /*把菜单加入盒子容器*/
        gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 3);
        /***********************************以下是信号处理部分************************************/
    
        /*关闭窗口时退出主循环*/
        g_signal_connect_swapped(G_OBJECT(window),"destroy",G_CALLBACK(gtk_main_quit), NULL);
    
        /***********************************以下是显示控件部分************************************/
        /*开始显示窗口*/
        //gtk_widget_show(window);
        gtk_widget_show_all(window);
    
    
        gtk_main();
        return 0;
    }

    六。添加状态栏,并点击任意菜单的时候在状态来显示内容

    #include <gtk/gtk.h>
    
    /*
      @Description: 从一个图片中获取信息得到pixbuf
      @param:       gchar filename
    */
    GdkPixbuf *create_pixbuf(const gchar * filename)
    {
        GdkPixbuf *pixbuf;
        GError *error = NULL;
        /*
         * 函数gdk_pixbuf_new_from_file() 从一个图片文件中加载图象数据,从而生成一个新的 pixbuf,
         * 至于文件中包含图象的格式,是由系统自动检测的。如果该函数返回值是NULL 的话,程序就会出现错误。
        */
        pixbuf = gdk_pixbuf_new_from_file(filename, &error);
        if(!pixbuf) {
            fprintf(stderr, "%s
    ", error->message);
            g_error_free(error);
        }
        return pixbuf;
    }
    
    /*点击菜单时,状态栏显示*/
    void menu_pressed(GtkWidget *widget, gpointer window)
    {
        gchar *str;
        str = g_strdup_printf("you clicked one menu item");
        gtk_statusbar_push(GTK_STATUSBAR(window),gtk_statusbar_get_context_id(GTK_STATUSBAR(window), str), str);
        g_free(str);
    }
    
    
    int main( int argc, char *argv[])
    {
        GtkWidget *window;
        GtkWidget *vbox;            //盒装容器
        GtkWidget *menubar;         //菜单栏
        GtkWidget *menutoggle, *menu_tog_toggle,*menu_tog_toolbar, *menu_tog_statusbar;  //界面开关菜单
        //GtkWidget *menu_about, *menu_about_us;  //帮助菜单
        GtkWidget *statusbar;       //状态栏
    
        /*初始化整个GTK+程序,是每一个GTK+程序必不可少的部分*/
        gtk_init(&argc, &argv);
        /*这里生成了一个窗口构件——GtkWindow,GTK_WINDOW_TOPLEVEL包含窗口的标题栏和边框,同意用窗口管理器来进行管理*/
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
        /*设置窗口标题*/
        gtk_window_set_title(GTK_WINDOW(window), "机器人");
        /*设置窗口默认大小*/
        gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);
        /*
         * 设置窗口在显示器中的位置为居中。
         *   GTK_WIN_POS_NONE            :不固定
         *   GTK_WIN_POS_CENTER          : 居中
         *   GTK_WIN_POS_MOUSE           : 出现在鼠标位置
         *   GTK_WIN_POS_CENTER_ALWAYS   : 窗口改变大小的时候仍然居中
        */
        gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
    
        /*函数gtk_window_set_icon() 是为窗口设置图标用的,函数create_pixbuf是我们自定义的,目的是从一个图片中获取信息得到pixbuf。*/
        gtk_window_set_icon(GTK_WINDOW(window), create_pixbuf(argv[1]));
    
        /*创建一个盒装容器并添加到窗口中*/
        vbox = gtk_vbox_new(FALSE, 0);
        gtk_container_add(GTK_CONTAINER(window), vbox);
    
        /*创建菜单*/
        menubar = gtk_menu_bar_new();   //代表整个菜单,是一个menu shell
    
        menutoggle = gtk_menu_new();   //这里代表第一列菜单toggle ,也是一个menu shell
        menu_tog_toggle = gtk_menu_item_new_with_label("导航");
        menu_tog_toolbar = gtk_menu_item_new_with_label("清除地图"); //toggle 菜单中子项
        menu_tog_statusbar = gtk_menu_item_new_with_label("创建地图");
    
        gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_tog_toggle), menutoggle);  //widget toggle菜单加入 menutoggle menu shell
        gtk_menu_shell_append(GTK_MENU_SHELL(menutoggle), menu_tog_toolbar);
        gtk_menu_shell_append(GTK_MENU_SHELL(menutoggle), menu_tog_statusbar);
    
        gtk_menu_shell_append(GTK_MENU_SHELL(menubar), menu_tog_toggle);
    
    
        /*把菜单加入盒子容器*/
        gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 4);
    
        statusbar = gtk_statusbar_new();
        gtk_box_pack_end(GTK_BOX(vbox), statusbar, FALSE, TRUE, 1);
        /***********************************以下是信号处理部分************************************/
    
        /*关闭窗口时退出主循环*/
        g_signal_connect_swapped(G_OBJECT(window),"destroy",G_CALLBACK(gtk_main_quit), NULL);
        g_signal_connect(G_OBJECT(menu_tog_toolbar),"activate",G_CALLBACK(menu_pressed), G_OBJECT(statusbar));
        g_signal_connect(G_OBJECT(menu_tog_statusbar),"activate",G_CALLBACK(menu_pressed), G_OBJECT(statusbar));
    
        /***********************************以下是显示控件部分************************************/
        /*开始显示窗口*/
        //gtk_widget_show(window);
        gtk_widget_show_all(window);
    
    
        gtk_main();
        return 0;
    }

     七。添加工具栏,并给“退出”按钮加入信号

    #include <gtk/gtk.h>
    
    /*
      @Description: 从一个图片中获取信息得到pixbuf
      @param:       gchar filename
    */
    GdkPixbuf *create_pixbuf(const gchar * filename)
    {
        GdkPixbuf *pixbuf;
        GError *error = NULL;
        /*
         * 函数gdk_pixbuf_new_from_file() 从一个图片文件中加载图象数据,从而生成一个新的 pixbuf,
         * 至于文件中包含图象的格式,是由系统自动检测的。如果该函数返回值是NULL 的话,程序就会出现错误。
        */
        pixbuf = gdk_pixbuf_new_from_file(filename, &error);
        if(!pixbuf) {
            fprintf(stderr, "%s
    ", error->message);
            g_error_free(error);
        }
        return pixbuf;
    }
    
    /*点击菜单时,状态栏显示*/
    void menu_pressed(GtkWidget *widget, gpointer window)
    {
        gchar *str;
        str = g_strdup_printf("you click one menu item");
        gtk_statusbar_push(GTK_STATUSBAR(window),gtk_statusbar_get_context_id(GTK_STATUSBAR(window), str), str);
        g_free(str);
    }
    
    
    int main( int argc, char *argv[])
    {
        GtkWidget *window;
        GtkWidget *vbox;            //盒装容器
        GtkWidget *menubar;         //菜单栏
        GtkWidget *menutoggle, *menu_tog_toggle,*menu_tog_toolbar, *menu_tog_statusbar;  //界面开关菜单
        //GtkWidget *menu_about, *menu_about_us;  //帮助菜单
        GtkWidget *toolbar;         //工具栏
        GtkToolItem *tool_exit, *tool_sep,*tool_about;
        GtkWidget *statusbar;       //状态栏
    
        /*初始化整个GTK+程序,是每一个GTK+程序必不可少的部分*/
        gtk_init(&argc, &argv);
        /*这里生成了一个窗口构件——GtkWindow,GTK_WINDOW_TOPLEVEL包含窗口的标题栏和边框,同意用窗口管理器来进行管理*/
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
        /*设置窗口标题*/
        gtk_window_set_title(GTK_WINDOW(window), "机器人");
        /*设置窗口默认大小*/
        gtk_window_set_default_size(GTK_WINDOW(window), 500, 400);
        /*
         * 设置窗口在显示器中的位置为居中。
         *   GTK_WIN_POS_NONE            :不固定
         *   GTK_WIN_POS_CENTER          : 居中
         *   GTK_WIN_POS_MOUSE           : 出现在鼠标位置
         *   GTK_WIN_POS_CENTER_ALWAYS   : 窗口改变大小的时候仍然居中
        */
        gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
    
        /*函数gtk_window_set_icon() 是为窗口设置图标用的,函数create_pixbuf是我们自定义的,目的是从一个图片中获取信息得到pixbuf。*/
        gtk_window_set_icon(GTK_WINDOW(window), create_pixbuf(argv[1]));
    
        /*创建一个盒装容器并添加到窗口中*/
        vbox = gtk_vbox_new(FALSE, 0);
        gtk_container_add(GTK_CONTAINER(window), vbox);
    
        /*创建菜单*/
        menubar = gtk_menu_bar_new();   //代表整个菜单,是一个menu shell
    
        menutoggle = gtk_menu_new();   //这里代表第一列菜单toggle ,也是一个menu shell
        menu_tog_toggle = gtk_menu_item_new_with_label("View");
        menu_tog_toolbar = gtk_menu_item_new_with_label("show Toolbar"); //toggle 菜单中子项
        menu_tog_statusbar = gtk_menu_item_new_with_label("show Statusbar");
    
        gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_tog_toggle), menutoggle);  //widget toggle菜单加入 menutoggle menu shell
        gtk_menu_shell_append(GTK_MENU_SHELL(menutoggle), menu_tog_toolbar);
        gtk_menu_shell_append(GTK_MENU_SHELL(menutoggle), menu_tog_statusbar);
    
        gtk_menu_shell_append(GTK_MENU_SHELL(menubar), menu_tog_toggle);
    
    
        //创建工具栏
        toolbar = gtk_toolbar_new();
        gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS); //设置工具栏样式为图标
        gtk_container_set_border_width(GTK_CONTAINER(toolbar), 0);      //工具栏边框大小
    
        tool_exit = gtk_tool_button_new_from_stock(GTK_STOCK_QUIT);     //工具栏中的 “退出” 按钮
        gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_exit, -1);
    
        tool_sep = gtk_separator_tool_item_new();                       //工具栏中按钮之间的分割线
        gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_sep, -1);
    
        tool_about = gtk_tool_button_new_from_stock(GTK_STOCK_HELP);    //工具栏中的“关于” 按钮
        gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_about, -1);
    
    
        statusbar = gtk_statusbar_new();
        /*把菜单加入盒子容器*/
        gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 1);
        /*把工具栏加入盒子容器*/
        gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0);
        /*把状态栏加入盒子最下面*/
        gtk_box_pack_end(GTK_BOX(vbox), statusbar, FALSE, TRUE, 1);
    
    
        /***********************************以下是信号处理部分************************************/
        /*关闭窗口时退出主循环*/
        g_signal_connect_swapped(G_OBJECT(window),"destroy",G_CALLBACK(gtk_main_quit), NULL);
        g_signal_connect(G_OBJECT(tool_exit), "clicked",G_CALLBACK(gtk_main_quit), NULL);
    
        g_signal_connect(G_OBJECT(menu_tog_toolbar),"activate",G_CALLBACK(menu_pressed), G_OBJECT(statusbar));
        g_signal_connect(G_OBJECT(menu_tog_statusbar),"activate",G_CALLBACK(menu_pressed), G_OBJECT(statusbar));
    
        /***********************************以下是显示控件部分************************************/
        /*开始显示窗口*/
        //gtk_widget_show(window);
        gtk_widget_show_all(window);
    
    
        gtk_main();
        return 0;
    }

    八。窗口背景设置

        #include <gtk/gtk.h>  
          
        /* 功能:  设置背景图 
         * widget: 主窗口 
         * w, h:   图片的大小 
         * path:  图片路径 
         */  
        void chang_background(GtkWidget *widget, int w, int h, const gchar *path)  
        {  
            gtk_widget_set_app_paintable(widget, TRUE);     //允许窗口可以绘图  
            gtk_widget_realize(widget);   
          
            /* 更改背景图时,图片会重叠 
             * 这时要手动调用下面的函数,让窗口绘图区域失效,产生窗口重绘制事件(即 expose 事件)。 
             */  
            gtk_widget_queue_draw(widget);  
          
            GdkPixbuf *src_pixbuf = gdk_pixbuf_new_from_file(path, NULL);   // 创建图片资源对象  
            // w, h是指定图片的宽度和高度  
            GdkPixbuf *dst_pixbuf = gdk_pixbuf_scale_simple(src_pixbuf, w, h, GDK_INTERP_BILINEAR);  
          
            GdkPixmap *pixmap = NULL;  
          
            /* 创建pixmap图像;  
             * NULL:不需要蒙版;  
             * 123: 0~255,透明到不透明 
             */  
            gdk_pixbuf_render_pixmap_and_mask(dst_pixbuf, &pixmap, NULL, 128);  
            // 通过pixmap给widget设置一张背景图,最后一个参数必须为: FASLE  
            gdk_window_set_back_pixmap(widget->window, pixmap, FALSE);  
          
            // 释放资源  
            g_object_unref(src_pixbuf);  
            g_object_unref(dst_pixbuf);  
            g_object_unref(pixmap);  
        }  
          
        int main( int argc, char *argv[])  
        {  
            gtk_init(&argc, &argv);  
          
            //主窗口操作  
            GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);  
          
            gtk_window_set_title(GTK_WINDOW(window), "设置窗口背景图");  
            gtk_widget_set_size_request(window, 500, 450);  
          
            chang_background(window, 500, 400, argv[1]);    // 设置窗口背景图  
          
            gtk_widget_show_all(window); // 显示所有部件  
          
            gtk_main();  
              
            return 0;  
        } 

    九。

    绘图事件

     

    GTK界面只要有图片的地方,其底层实际上是通过绘图实现的,所以,我们很有必要学习一下绘图,这里我们使用 Cairo 进行相应的绘图操作。


    Cairo是用于绘制二维矢量图形的跨平台图形库,采用 C 语言实现,又被许多其它计算机语言所绑定。我们可以使用Cairo库在窗口中绘图,也可以用于生成PNG图片、PDF、PostScript、SVG文件。Cairo同时也是自由软件库,自GTK+2.8版本开始,Cairo成为GTK+库的一部分。


    绘图实际上也是事件的一种,GTK中,绘图事件也叫曝光事件。


    绘图时所触发的信号:expose-event

    只要触发曝光事件信号"expose-event",就会自动调用所连接的回调函数。


    这里需要注意的是,曝光事件信号 "expose-event" 默认的情况下,是自动触发的(当然也可以人为触发),就算我们不作任何操作,"expose-event"信号也有可能自动触发。前面我们学习中,我们按一下按钮就人为触发 "clicked" 信号,按一下鼠标人为触发 "button-press-event" 信号,如果我们不操作按钮,不操作鼠标,其对应的信号永远不会触发。


    曝光事件信号 "expose-event" 什么时候会自动触发呢?

    窗口状态(移动,初始化,按按钮……)改变,只用我们肉眼能看到窗口上有变化,它都会自动触发曝光事件信号"expose-event",然后就自动会调用它所连接的回调函数,但是,它不是刷新窗口的全部区域,它是按需要局部刷新,哪儿变化了就刷新那个变化的区域。


    当然我们也可以人为触发曝光事件信号"expose-event",并且指定刷图区域:

    触发信号,并且刷新图片的整个区域:

    void gtk_widget_queue_draw(GtkWidget *widget );

    widget:控件指针

    触发信号,并指定刷图区域:

    void  gtk_widget_queue_draw_area(
    GtkWidget *widget,
    gint x,
    gint y,
    gint width,
    gint height);

    widget:控件指针

    x, y:刷图的起点坐标

    width, height:刷图的宽、高

    需要注意的是,我们绘图的操作不是写在任何函数都行,尽量在曝光事件信号 "expose-event" 所连接的回调函数里进行相应的绘图操作。

    gboolean callback( GtkWidget *widget,       
    GdkEventExpose *event, 
    gpointer data )
    {
    // 绘图的相关操作
    ……
    
    return FALSE; // 尽量返回FALSE
    }


    如果窗口里有其它控件,回调函数必须返回FALSE,否则窗口里的控件会被绘图覆盖。


    使用 Cairo , 需要包含的头文件:#include <cairo.h>。


    创建Cairo环境:

    cairo_t *gdk_cairo_create( GdkDrawable *drawable ); 

    drawable:绘图区域

    返回值:cairo绘图环境指针


    注意:如果给窗口绘图,窗口本身不能绘图,窗口本质上是一个结构体,里面有个window成员,这个window成员才是真正的绘图区域。

    如:

    GtkWidget *w = gtk_window_new( GTK_WINDOW_TOPLEVEL );
    cairo_t *cr = gdk_cairo_create(w->window); // 注意传的参数

    回收资源: 

     

    void cairo_destroy(cairo_t *cr);

    参数:cairo绘图环境指针


    设置画图的图片:

    void gdk_cairo_set_source_pixbuf(
    cairo_t *cr, 
    const GdkPixbuf *pixbuf, 
    double pixbuf_x, 
    double pixbuf_y );

    cr:cairo绘图环境指针

    pixbuf:图片资源对象

    pixbuf_x,pixbuf_y:画图的起点位置

     

    绘制设置好的图片:

    void cairo_paint(cairo_t *cr);

    cr:cairo绘图环境指针

    注意:如果绘制图片后想继续写字或画线,必须手动设置画笔颜色( cairo_set_source_rgb() ), 否则,字体或线条会被图片覆盖。

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

    void gtk_widget_set_app_paintable(
    GtkWidget *widget, 
    gboolean app_paintable )

    widget:控件指针

    app_paintable:TRUE允许绘图,FALSE不允许


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

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

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

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

    绘图流程:

    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;  
        }  
     
  • 相关阅读:
    第 17 章 责任链模式【Chain of Responsibility Pattern】
    第 16 章 观察者模式【Observer Pattern】
    第 15 章 组合模式【Composite Pattern】
    第 14 章 迭代器模式【Iterator Pattern】
    第 13 章 装饰模式【Decorator Pattern】
    第 12 章 命令模式【Command Pattern】
    第 11 章 桥梁模式【Bridge Pattern】
    第 10 章 建造者模式【Builder Pattern】
    编写高质量代码改善C#程序的157个建议——导航开篇
    C#实现简易ajax调用后台方法
  • 原文地址:https://www.cnblogs.com/zxouxuewei/p/7204644.html
Copyright © 2011-2022 走看看