我是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;
}
答案 0 :(得分:3)
这里有几点评论:
每次创建Gen
对象时都会分配Gen :: pix。它是相同的pixbuf,但你创建一个,然后使用缩放功能(意味着你正在泄漏原始pixbuf的内存),并为每个Gen
对象创建一个。这实际上是非常有效的,所以使用静态pix
成员,加载然后缩放pixbuf并修复内存泄漏将允许你只执行一次。
然后:你在绘制处理程序中调用gdk_cairo_create
,但是从GTK 3开始,你应该将cairo上下文作为draw
信号回调中的输入参数。我看到你通过动作事件调用自定义draw
方法,这不是GTK +绘图堆栈的工作方式!
做得对:
draw
信号Gen
个对象的位置,然后为绘图区域调用gtk_widget_queue_draw
。这将为您发出draw
信号。draw
信号的回调中,然后在您给出的cairo上下文中重绘Gen
个对象。gtk_widget_queue_draw_area
或gtk_widget_queue_draw_region
而不是gtk_widget_queue_draw
。然后,您将在draw
回调中收到的cairo上下文中获得预先计算的剪辑区域。通过这些提示,您可以确切地确定需要重新绘制图像的哪个部分,并避免不必要的工作。请阅读官方文档中的The GTK+ Drawing Model。