我对GTK真的很陌生,我正在尝试学习如何处理我想到的项目。

问题是,我可以设法制作一个将“Generators”放置在窗口上的应用程序……每次我在屏幕上单击时,该应用程序都会在窗口中放置一个gen,并准备另一个可以放置的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;
}

最佳答案

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

然后:您在绘制处理程序中调用gdk_cairo_create,但是从GTK 3开始,应该在draw信号回调中获取cairo上下文作为输入参数。我看到您正在通过运动事件调用自定义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

    关于c++ - 绘制时GTK闪烁,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46480555/

    10-11 04:36
    查看更多