LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1119|回复: 4

诚心请教gtk 绘图 不显示的问题

[复制链接]
发表于 2008-1-21 04:19:32 | 显示全部楼层 |阅读模式
我要用Gtk实现一个模拟交通系统的动画,即车辆在十字路口会根据交通灯停下或者行驶。
我采用的方式是类似于VC下的动画制作方式,先在pixmap中将相关的图形绘制好,再在expose_event的处理函数中将pixmap贴上到drawing_area,驱动动画进行的是用idle回调函数,在idle回调函数中通过计数达到一定数值就执行相关的绘图函数(run,display_car,draw_background etc),当将所有的图形都重新绘制在pixmap中后就在run中调用 gtk_widget_queue_draw函数激发expose_event的事件,将pixmap贴上到drawing_area上面。
我遇到的问题是,我在run,display,draw_background里面在pixmap上绘图的图形完全显示了,但我用anjuta调试的时候的确是执行到这些函数里面的绘图语句,这个问题困扰多天了,恳请哪位高人能指点一二。是不是gtk的绘图机制有哪些地方要特别注意的...


在调试的时候终端会出现 gtk-critical...的提示,说 GDK_IS_GC**Failed

下面是相关的代码,下面的代码纯粹是一个框架,用于测试我这种方式实现的机制:

此处是定义的相关数据结构:(可忽略)
enum  _CarDirection {RightToLeft,LeftToRight,UptoDown,DownToUp};
typedef enum _CarDirection CarDirection;

enum _LightState {Red,Mediate,Green};
typedef enum _LightState LightState;


struct _Car
{
        gint speed;
        CarDirection direction;
        GdkPoint centralPoint;
};
typedef struct _Car Car;



struct _CarLink
{
        Car car;
        struct _CarLink *link;
};
typedef struct _CarLink CarLink;


struct _TrafficLight
{
        LightState vertical;
        LightState horizontal;
};
typedef struct _TrafficLight TrafficLight;


struct _Channel
{
        CarLink* cars;
        gint count;
};
typedef struct _Channel Channel;


struct _TrafficChannels
{
        Channel righttoleft;
        Channel lefttoright;
        Channel uptodown;
        Channel downtoup;
};
typedef struct _TrafficChannels TrafficChannels;


struct _EnvironmentViriable
{
        gint tCheck;
        gint iCarTotal;
        gint iCarLength;
        GdkGC *gc;
        GdkGC *bgGC;
        GtkWidget *da;
};
typedef struct _EnvironmentViriable EnvironmentViriable;



************************************************************
定义的测试全局变量:
GdkPixmap *pixmap=NULL;

EnvironmentViriable ev;

Car car;



*************************************************************
相关的函数:

//获取颜色,用于偷懒
GdkColor get_color(int red,int green,int blue)
{
        GdkColor color;
        color.red=red;
        color.green=green;
        color.blue=blue;
       
        return color;
}


//退出的销毁函数
void destroy(GtkWidget *widget,gpointer data)
{       
        gtk_main_quit();
}


//相关变量初始化函数
void init(GtkWidget* widget)
{
        GdkColor color=get_color(0,0,65535);
       
        ev.tCheck=0;
       
        ev.gc=gdk_gc_new(widget->window);
        gdk_gc_set_rgb_fg_color(ev.gc,&color);
        gdk_gc_set_rgb_bg_color(ev.gc,&color);
       
        color=get_color(20000,20000,20000);
        ev.bgGC=gdk_gc_new(widget->window);
        gdk_gc_set_rgb_bg_color(ev.bgGC,&color);
       
       
        car.centralPoint.x=0;
        car.centralPoint.y=0;
       
        ev.da=widget;
       
       
}


//简单地函数背景
void draw_background(GtkWidget* widget)
{
        gdk_draw_rectangle(pixmap,ev.gc,TRUE,0,0,widget->allocation.width,widget->allocation.height);
}



//测试,用于绘制车辆
void display_car(GtkWidget* widget)
{
        GdkColor color=get_color(30000,30000,65535);
        gdk_gc_set_rgb_fg_color(ev.gc,&color);
        gdk_draw_rectangle(pixmap,ev.gc,TRUE,car.centralPoint.x,300,10,10);
}


//运行函数
void run(GtkWidget* widget)
{
        car.centralPoint.x+=15;
       
        draw_background(widget);
        display_car(widget);
        gtk_widget_queue_draw(widget);
}



gboolean configure_event(GtkWidget        *widget,GdkEventConfigure *event)
{
        if(pixmap)
                g_object_unref(pixmap);
               
        pixmap=gdk_pixmap_new(widget->window,widget->allocation.width,widget->allocation.height,-1);
        gdk_draw_rectangle(pixmap,widget->style->white_gc,TRUE,0,0,widget->allocation.width,widget->allocation.height);       

        return TRUE;
}



gboolean expose_event(GtkWidget *widget,GdkEventExpose *event,gpointer data)
{
        gdk_draw_drawable(widget->window,widget->style->fg_gc[GTK_WIDGET_STATE(widget)],pixmap,event->area.x,event->area.y,event->area.x,event->area.y,event->area.width,event->area.height);
        return FALSE;
}



//idle时候调用的回调函数
gint idle_callback(gpointer window)
{
        ev.tCheck++;
       
        if(ev.tCheck>20)
        {
                ev.tCheck=0;
                run(ev.da);
        }
        return TRUE;
}




****************************************************************************************
main函数了

int main (int argc, char *argv[])
{
        GtkWidget *window;
        GtkWidget *drawing_area;
        GtkWidget *vbox;


#ifdef ENABLE_NLS
        bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
        bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
        textdomain (GETTEXT_PACKAGE);
#endif

       
        gtk_set_locale ();
        gtk_init (&argc, &argv);

        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
        gtk_window_set_title(GTK_WINDOW(window),"Linux Car");
        gtk_widget_set_size_request(window,1000,700);
        gtk_window_set_resizable(window,FALSE);
        g_signal_connect(G_OBJECT(window),"destroy",G_CALLBACK(destroy),NULL);
       
       
        vbox=gtk_vbox_new(FALSE,0);
        gtk_container_add(GTK_CONTAINER(window),vbox);
        gtk_widget_show(vbox);
       
        g_signal_connect(G_OBJECT(window),"destroy",G_CALLBACK(destroy),NULL);
       
        drawing_area=gtk_drawing_area_new();
        gtk_drawing_area_size(GTK_DRAWING_AREA (drawing_area),1000,700);
        gtk_box_pack_start(GTK_BOX(vbox),drawing_area,TRUE,TRUE,0);
        gtk_widget_show(drawing_area);
       
       
        g_signal_connect(G_OBJECT(drawing_area),"expose_event",G_CALLBACK(expose_event),NULL);
        g_signal_connect(G_OBJECT(drawing_area),"configure_event",G_CALLBACK(configure_event),NULL);
        gtk_widget_set_events(drawing_area,GDK_EXPOSURE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);       
        init(drawing_area);
        g_idle_add(idle_callback,(gpointer)drawing_area);
       
       
        gtk_widget_show (window);

        gtk_main ();
}
发表于 2008-1-21 04:40:31 | 显示全部楼层
肯定是某个地方的指针类型用错了。另外,你这个g_idle_add是不是可以使用g_timeout_add更好些呢?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-1-21 14:26:34 | 显示全部楼层
为什么说肯定啊?你以前也遇到过这种问题么?

用g_idle_add是考虑到性能方面的因素,而且g_timeout_add的话时间上的话不一定是精确的,而且我这个是没有交互功能的,也就是不会人工地触发什么事件之类的,所以使用g_idle_add。。
回复 支持 反对

使用道具 举报

发表于 2008-1-22 15:02:41 | 显示全部楼层
Post by StephenChen;1809551
为什么说肯定啊?你以前也遇到过这种问题么?

用g_idle_add是考虑到性能方面的因素,而且g_timeout_add的话时间上的话不一定是精确的,而且我这个是没有交互功能的,也就是不会人工地触发什么事件之类的,所以使用g_idle_add。。


我是从你给出的错误提示判断的:GDK_IS_GC,这个就是用来判断某个指针是否是GdkGC类型的。

g_idle_add会占用大量的CPU吧?它是只要在CPUidle的时候就会调用,所以导致你的CPU根本就不会idle了。

g_timeout_add在时间上还不够精确?我看它是用毫秒做为计算单位的。我没仔细看你的代码,但是发现你是使用一个简单地计数器。这似乎跟时间没什么关系的,如果非要说跟时间相关的话,那就是执行这个回调函数的时间。从时间精度上来说,这个肯定赶不上g_timeout_add的吧?

当然,这只是我的看法。在你的应用中,我说的这些不一定适用。只是希望这些信息会对你有用。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2008-1-24 10:58:13 | 显示全部楼层
其实我也犹豫过这两种方法,不过结果还是按照书本的方法,用了g_idle_add。。
那个问题解决了,把init函数放在expose_event中就可以了。
谢谢你的关注和指导!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表