Re: the right way to draw in a drawingarea
- From: "Josepo Urrutia" <find_all hotmail com>
- To: pjdavis engineering uiowa edu
- Cc: gtkmm-list gnome org
- Subject: Re: the right way to draw in a drawingarea
- Date: Tue, 11 Oct 2005 13:06:20 +0000
To use the Gtk::DrawingArea widget to display a custom image or pixmap I
wrote a class that does this for me ( the code is attached).
The class is in Spanish (sorry no time to translate the code now), but the
code is simple enough to understand it quite well.
To do the drawing class I inherint from objeto_drawingarea and overwrite the
configurar (configure) function so this function writes what we need to the
objeto_drawingarea::pixmap.
Then when we want to paint the widget we simply have to call repintar
(repaint).
Basically It uses queue_draw() to paint the pixmap created by the configure
function into the DrawingArea window.
It also controls some basic events (on_expose,on_realize,on_size_alloc...).
The code is not perfect ( I'm not perfect and my code even less) but hope it
helps a bit.
From: Paul Davis <pjdavis engineering uiowa edu>
To: "Foster, Gareth" <gareth foster siemens com>
CC: gtkmm-list gnome org
Subject: Re: the right way to draw in a drawingarea
Date: Tue, 11 Oct 2005 05:11:46 -0500
Foster, Gareth wrote:
the display flickers, even when drawing a simple square.
Doesn't this often mean you need to be double buffering?
_______________________________________________
gtkmm-list mailing list
gtkmm-list gnome org
http://mail.gnome.org/mailman/listinfo/gtkmm-list
This is a point I am completely unsure about. I haven't the foggiest on
Gtk internals and the ramifications of a simple call such as
draw_rectangle. I've used double buffering in both OpenGL and Java. I've
just never really seen any real reference to it in gtk. Now that I've had
a couple beers, I seem to rememeber some reference to getting an offscreen
graphics context, drawing to that, and then switching the main gc with it
back and forth. But I could be completely making that up. ( the beer )
Double buffering isn't really that hard of a concept. I'm just not sure of
if its needed. Because its more than possible that gtk has its own
buffering scheme burried somewhere. I've actually written a couple
programs to animate image data using Gtkmm. I've never had a problem with
flickering that wasn't because I was doing something silly like clearing
and then redrawing. So the answer is I dunno. Its possible. If I get
time I'll write a test program to try and play with the idea.
And if I had thought to take a moment to google something as silly as gtkmm
double buffering, I would have noticed that the gtkmm docs specify that
widgets are double buffered by default. In which case, no double buffering
will not solve this problem cause its already being done. Which goes to
show that yes, I was making up the graphics context thing. Must be
something from java I was thinking of.
http://www.gtkmm.org/docs/gtkmm-2.4/docs/reference/html/classGtk_1_1Widget.html#a175
In other news, Unleashed wasn't half bad if anyone cares.
Cheers,
Paul
_______________________________________________
gtkmm-list mailing list
gtkmm-list gnome org
http://mail.gnome.org/mailman/listinfo/gtkmm-list
#include "objeto_drawingarea.hh"
/* ************************
objeto_drawingarea
********************* */
objeto_drawingarea::objeto_drawingarea()
{
// Lo primero es inicializar
this->inicializar();
} // Fin de constructor
/* **************************
~objeto_drawingarea
*********************** */
objeto_drawingarea::~objeto_drawingarea()
{
//fprintf(stderr,"INICIO Destructor objeto_drawingarea\n");
//fprintf(stderr,"FIN Destructor objeto_drawingarea\n");
} // Fin del constructor
/* ******************
inicializar
*************** */
// Funcion que inicializa los valores de la clase
void objeto_drawingarea::inicializar(void)
{
// Inicializamos los colores minimos
for(gint i=0;i<NUM_COLOR;i++)
this->colores.push_back( Gdk::Color("white") );
this->colores[0] = Gdk::Color("gray");
this->colores[1] = Gdk::Color("black");
this->colores[2] = Gdk::Color("aquamarine4");
this->colores[3] = Gdk::Color("blue");
// Ponemos los colores de fondo y de "frente"
this->bg=0;this->fg=1;
// Ponemos los signals
this->signal_expose_event().connect(sigc::mem_fun(*this, &objeto_drawingarea::on_expose_event));
this->signal_realize().connect(sigc::mem_fun(*this,&objeto_drawingarea::on_realize));
this->signal_size_allocate().connect(sigc::mem_fun(*this, &objeto_drawingarea::on_size_alloc));
} // Fin de inicializar
/* *****************
meter_color
************** */
// Funcion q permite meter un color nuevo al vector de colores
gint objeto_drawingarea::meter_color(Gdk::Color color)
{
// Comprobamos si el color ya existe, ir pa na es tonteria
int i=0;
int size=this->colores.size();
int ret=0;
int r,g,b;
r=color.get_red();
g=color.get_green();
b=color.get_blue();
while((i<size)&&(ret==0))
{
if((r==this->colores[i].get_red())&&(g==this->colores[i].get_green())&&(b==this->colores[i].get_blue()))
ret=1;
else
i++;
}
// Comprobamos si hemos encontrado el color
if(ret!=0)
{
// El color ya existe
return i; // Devolvemos la posicion del color dentro del vector
}
// No existe el color lo metemos
this->colores.push_back(color);
this->colormap->alloc_color(this->colores[i]);
return i;
} // Fin de meter_color(Gdk::Color)
// Sobrecarga
gint objeto_drawingarea::meter_color(char *str)
{
if(!str)
{
this->error("meter_color : Cadena vacia");
return -1;
}
Gdk::Color color = Gdk::Color(str);
return this->meter_color(color);
} // Fin de meter_color(char *)
// Sobrecarga
gint objeto_drawingarea::meter_color(int r,int g, int b)
{
Gdk::Color color;
color.set_red(r*256);
color.set_green(g*256);
color.set_blue(b*256);
return this->meter_color(color);
} // Fin de meter_color(int,int,int)
/* *****************
crea_pixmap
************** */
// Funcion que crea el pixmap para contener la imagen a representar
gint objeto_drawingarea::crea_pixmap(void)
{
// Comprobamos q todo lo necesario existe y es correcto
if(this->window==0)
{
this->error("crea_pixmap: ERROR no se puede crear pixmap, window no definido");
return -1; // Window no definido
}
if((this->winw<=0)||(this->winh<=0))
{
this->error("crea_pixmap: ERROR no se puede crear pixmap, tamanyos incorrectos");
return -2; // Tamaños del pixmap incorrectos
}
if(this->colormap==0)
{
this->error("crea_pixmap: ERROR no se puede crear pixmap, colormap no definido");
return -3; // Colormap no definido
}
// Cogemos el tamanyo de la ventana
this->window->get_geometry(this->winx,this->winy,this->winw,this->winh,this->wind);
// Definimos la imagen
// La imagen es del tamanyo de la ventana
this->pixmap = Gdk::Pixmap::create(this->window,this->winw,this->winh,this->window->get_depth());
// Le ponemos un colormap especifico
this->pixmap->set_colormap(this->colormap);
return 0; // Todo bien
} // Fin de crea_pixmap
/* **********************
on_realize
******************* */
// Funcion que se llama cuando se muestra la ventana por primera vez
void objeto_drawingarea::on_realize()
{
//fprintf(stderr,"INICIO on_realize\n");
// Esta funcion se utiliza para inicializar el entorno grafico
// We need to call the base on_realize()
Gtk::DrawingArea::on_realize ();
// Recogemos la ventana
this->window = this->get_window ();
// Guardamos la geometria de la ventana
this->window->get_geometry (this->winx,this->winy,this->winw,this->winh,this->wind);
// Creamos el contexto grafico
this->gc_ = Gdk::GC::create (this->window);
// Recogemos el mapa de colores
this->colormap = get_default_colormap ();
// Metemos todos los colores de la paleta
// OJO : La clase q herede debe inicializar la paleta al inicio
for(gint i=0;i<NUM_COLOR;i++)
{
this->colormap->alloc_color(this->colores[i]);
}
// Ponemos los colores de fondo y de "frente"
this->gc_->set_foreground(this->colores[this->fg]);
this->gc_->set_background(this->colores[this->bg]);
// Creamos el pixmap necesario para evitar el parpadeo
this->crea_pixmap();
//fprintf(stderr,"Informacion de pantalla : %c x %d y %d w %d h %d d %d\n",((this->window==0)?('N'):('T')),winx,winy,winw,winh,wind);
//fprintf(stderr,"FIN on_realize\n");
} // Fin de on_realize
/* **********************
on_expose_event
******************* */
// Funcion que se llama cada vez que algo que estaba encima se quita
bool objeto_drawingarea::on_expose_event(GdkEventExpose * ev)
{
//fprintf(stderr,"INICIO on_expose_event\n");
// Mandamos repintar el pixmap
this->window->draw_drawable(this->gc_,this->pixmap,0,0,0,0,this->winw,this->winh);
//fprintf(stderr,"FIN on_expose_event\n");
return true; // Permitimos que el evento suba al siguiente nivel
} // Fin de on_expose_event
/* *********************
on_size_alloc
****************** */
// Funcion que se llama cuando se cambia el tamanyo de la ventana
void objeto_drawingarea::on_size_alloc(Gtk::Allocation &al)
{
// Simplemente llamamos a cambio_ventana
this->on_cambio_ventana();
} // Fin de on_size_alloc
/* *****************************
on_cambio_ventana
************************** */
// Funcion q cambia el tamanyo de todos los elementos para ajustarse
// al tamanyo de ventana q da el entorno grafico
void objeto_drawingarea::on_cambio_ventana()
{
//fprintf(stderr,"INICIO on_cambio_ventana\n");
// Volvemos a crear el pixmap, el tamanyo de la ventana a cambiado
this->crea_pixmap();
// Debemos repintar
this->repintar();
//fprintf(stderr,"Nuevo tamanyo : x %d y %d w %d h %d d %d\n",winx,winy,winw,winh,wind);
//fprintf(stderr,"FIN on_cambio_ventana\n");
} // Fin de on_cambio_ventana
/* **********************
configurar
******************* */
// Funcion que crea el pixmap ha mostrar
gint objeto_drawingarea::configurar(void)
{
//fprintf(stderr,"INICIO configurar\n");
// Ponemos una funcion por defecto q pone el pixmap a blanco
// Comprobamos posibles errores
if(this->window==0)
{
this->error("configurar : Window no definido");
return -1;
}
if(this->pixmap==0)
{
this->error("configurar : Pixmap no definido");
return -2;
}
if(this->gc_==0)
{
this->error("configurar : GC no definido");
return -3;
}
if((this->winw<=0)||(this->winh<=0))
{
this->error("configurar : Tamanyos incorrectos");
return -4;
}
// Todo bien podemos crear el pixmap
// Limpiamos el pixmap
this->gc_->set_foreground(this->colores[this->bg]);
this->pixmap->draw_rectangle(this->gc_,true,0,0,this->winw,this->winh);
//fprintf(stderr,"FIN configurar\n");
} // Fin de configurar
/* *****************
repintar
************** */
// Funcion q repinta el pixmap en pantalla
gint objeto_drawingarea::repintar(void)
{
//fprintf(stderr,"INICIO repintar\n");
gint dev;
// Reconstruimos el pixmap
dev=this->configurar();
// Dibujamos en el window el pixmap
if(dev==0) // solo si la configuracion del pixmap ha ido bien
this->window->draw_drawable(this->gc_,this->pixmap,0,0,0,0,this->winw,this->winh);
// Obligamos a redibujar el window
this->queue_draw();
//fprintf(stderr,"FIN repintar\n");
return dev; // Si es 0 todo bien, si es menor q 0 mal
} // Fin de repintar
/* **************
error
*********** */
// Funcion q sirve para controlar los errores q se han estado dando
void objeto_drawingarea::error(gchar *linea)
{
// En esta funcion podemos decidir q tratamiento dar a los errores
// sacarlos por pantalla a un fichero ...etc.
std::cout<<"ERROR EN objeto_drawingarea.cc\n";
std::cout<<linea<<"\n";
} // Fin de error
/* *******************************************
objeto_drawingarea
Clase para la realizacion rapida de
drawingareas simples para dibujar
en ellas
**************************************** */
#ifndef _OBJETO_DRAWINGAREA_HH
#define _OBJETO_DRAWINGAREA_HH
// Includes standar
#include <iostream>
// Include propio de la gtkmm
#include <gtkmm/drawingarea.h>
// Defines propios
// Numero de colores de la paleta
#define NUM_COLOR 32
class objeto_drawingarea : public Gtk::DrawingArea
{
public:
// Constructor
objeto_drawingarea();
// Destructor
virtual ~objeto_drawingarea();
// Variables para pintar
Glib::RefPtr<Gdk::GC> gc_;
gint fg,bg;
Glib::RefPtr<Gdk::Window> window;
Glib::RefPtr < Gdk::Colormap > colormap;
// Paleta de colores a utilizar
std::vector <Gdk::Color> colores;
// Para guardar la imagen y evitar el parpadeo
Glib::RefPtr<Gdk::Pixmap> pixmap;
// window geometry: x, y, width, height, depth
gint winx,winy,winw,winh,wind;
// Para repintar el pixmap
gint repintar(void);
// Funcion q permite meter un color
gint meter_color(char *);
gint meter_color(int,int,int);
gint meter_color(Gdk::Color);
protected:
private:
// Funcion que inicializa la clase
void inicializar(void);
// Funcion q crea el pixmap para contener la imagen a representar
gint crea_pixmap(void);
// Funcion q se llama cuando se muestra por primera vez el objeto
void on_realize();
// Funcion que se llama cuando algo se quita de encima y debemos repintar
bool on_expose_event(GdkEventExpose * ev);
// Estas funciones permiten reconstruir el pixmap cuando la ventana del
// drawingarea cambia de tamanyo
// Esta pensado para los paneles y para cuando la ventana cambia de tamanyo
void on_size_alloc(Gtk::Allocation &);
void on_cambio_ventana();
// Funcion que debe implementar la clase q hereda
// Aqui se debera meter todo el codigo q genera la imagen dentro del pixmap
virtual gint configurar(void)=0;
// Funcion para el tratamiento de errores
void error(gchar *linea);
};
#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]