绘图时GTK闪烁

时间:2017-09-29 01:40:42

标签: c++ gtk drawing gtk3 cairo

我是GTK的新手,我正在努力学习如何处理我想到的项目。

问题是,我可以设法制作一个应用程序,将“Generators”放在窗口上......每次我点击屏幕,应用程序都会在窗口中放置一个gen,然后准备另一个准备放置的窗口... 问题是当绘制所有生成器时程序闪烁... 每个gen都必须一直重绘,这就是我认为问题......这是代码......我怎样才能让它更快? ...提前致谢!!

    // gcc main.c -o main `pkg-config gtk+-3.0 --cflags --libs`
#include <gtk/gtk.h>
#include <stdlib.h>
#include <iostream>
#include <vector>

using namespace std;

class Gen{
public:
  int x;
  int y;
  GdkPixbuf *pix;
  GtkWidget *canvas;
  bool placed;

  Gen(GtkWidget *canvas){
    this->canvas=canvas;
    GError *err = NULL;
    pix = gdk_pixbuf_new_from_file("./Img/gen.png", &err);
    pix= gdk_pixbuf_scale_simple(pix,50,50, GDK_INTERP_BILINEAR);
    x=10;y=10;
    placed=0;
  }

  void draw(cairo_t *cr){
    gdk_cairo_set_source_pixbuf(cr, pix, x, y);
    cairo_paint(cr);
  }

  void updatePosition(int a, int b){
      if(placed==0){
        x=a-25;
        y=b-25;
        }
  }

  void place(){
      placed=1;
  }

};

class Map{
public:
    vector<Gen *> Gens;
    GtkWidget *window;
    GtkWidget *canvas;
    int xPointer,yPointer;

    Map(GtkWidget *_window, GtkWidget *_canvas){
        window=_window;
        canvas=_canvas;
    }

    void draw(){
        cairo_t *cr;
        cr = gdk_cairo_create (gtk_widget_get_window(canvas));
        cairo_set_source_rgb(cr, 1, 1, 1);
        cairo_rectangle(cr, xPointer-35, yPointer-35, 70, 70);
        cairo_paint(cr); 
        for(vector<Gen *>::const_iterator i=Gens.begin();i!=Gens.end();i++){
            (*i)->draw(cr);
        }
        cairo_destroy (cr);   
    }
    void place(){
        Gen *aux=Gens.back(); 
        aux->place();
        //Gens.push_back(new Gen(canvas));
    }
    void moving(int x,int y){
        xPointer=x;yPointer=y;
        if(Gens.size()==0){
            Gens.push_back(new Gen(canvas)); 
        }
        else if (Gens.back()->placed==1){
            Gens.push_back(new Gen(canvas));
        }
        Gen *aux=Gens.back();
        aux->updatePosition(x,y);
        this->draw();
        cout<<"Elementos -> "<<Gens.size()<<"\n";
    }
};





static gboolean
moving(GtkWidget *da, GdkEvent *event, gpointer data)
{

    int x, y;
    GdkModifierType state;
    gdk_window_get_device_position (gdk_event_get_window ((GdkEvent *) event),
                                    gdk_event_get_device ((GdkEvent *) event),
                                    &x, &y, &state);
    /*
    (void)event; (void)data;
    ((Gen *)da)->draw();*/
    Map *g=(Map *)data;
    g->moving(x,y);
}
static gboolean
placing (GtkWidget *da, GdkEvent *event, gpointer data)
{

    Map *g=(Map *)data;
    g->place();

}

int main ( int argc, char **argv) {


    GtkWidget *window;
    GtkWidget *canvas;
    gtk_init (&argc , &argv);
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_widget_set_size_request (window,
        500, 500);

    g_signal_connect (window, "destroy",
        G_CALLBACK (gtk_main_quit) , NULL);
    canvas = gtk_drawing_area_new ();
    Map *g=new Map(window,canvas);
    gtk_container_add (GTK_CONTAINER (window), canvas);
    gtk_widget_set_events(window, GDK_POINTER_MOTION_MASK);

    //g_signal_connect (canvas, "draw", G_CALLBACK (drawing), (gpointer *)g);
    g_signal_connect (window, "motion-notify-event", G_CALLBACK (moving), (gpointer *)g);
    g_signal_connect (window, "button-press-event", G_CALLBACK (placing), (gpointer *)g);

    //g_signal_connect (canvas, "motion-notify-event", (GCallback) on_window_draw, NULL);

    gtk_widget_set_app_paintable(canvas, TRUE);
    gtk_widget_show_all (window);
    gtk_main ();
    return 0;
}

1 个答案:

答案 0 :(得分:3)

这里有几点评论: 每次创建Gen对象时都会分配Gen :: pix。它是相同的pixbuf,但你创建一个,然后使用缩放功能(意味着你正在泄漏原始pixbuf的内存),并为每个Gen对象创建一个。这实际上是非常有效的,所以使用静态pix成员,加载然后缩放pixbuf并修复内存泄漏将允许你只执行一次。

然后:你在绘制处理程序中调用gdk_cairo_create,但是从GTK 3开始,你应该将cairo上下文作为draw信号回调中的输入参数。我看到你通过动作事件调用自定义draw方法,这不是GTK +绘图堆栈的工作方式!

做得对:

    主要是
  • ,连接到GtkDrawingArea的draw信号
  • 在您的动画回调中,只需更改Gen个对象的位置,然后为绘图区域调用gtk_widget_queue_draw。这将为您发出draw信号。
  • 在连接到draw信号的回调中,然后在您给出的cairo上下文中重绘Gen个对象。
  • 为了提高性能,您可以使用cairo裁剪功能,或者拨打gtk_widget_queue_draw_areagtk_widget_queue_draw_region而不是gtk_widget_queue_draw。然后,您将在draw回调中收到的cairo上下文中获得预先计算的剪辑区域。通过这些提示,您可以确切地确定需要重新绘制图像的哪个部分,并避免不必要的工作。

请阅读官方文档中的The GTK+ Drawing Model