[gtkmm] [gtkmm]Building gtkmm widget to plot 2D graphics



Hi there,

I am a fairly new gtkmm programmer, and I would like to use gtkmm to program a small audio analysis tool. I need several widgets on my own, that is a vumeter, a 'real time' spectrogram plot (by real time, I really mean it will be updated regularly) and a spectrum plot similar to those you can see an popular music player (alsaplayer, xmms, so on). Here are my questions: as far as I understand gtkmm for now (I have mainly used studied the online book), I should derive my widgets from a DrawingArea widget. But as I don't have much experience in GUI programming, I fail to see 'where' I should put my code, and how to draw my plots: - having studied a bit the vu meter of alsaplayer and jamin, two pure GTK programs, it seems like they use a pixmap. I am not sure to understand exactly what a pixmap is. For now, I understand one draws the plot into a pixmap, and after that, one draws the pixmap onto the widget. Is it correct ? Why not drawing directly in a windows ? - What is the best way to conceive a efficient widget with a 'bitmap' regularly updated ? Where should I put the code for the creation of the pixmap, the GC, etc ... ?

For now, here is what I have done : I managed to draw a vu meter similar to the alsaplayer one. My widget, derived from a DrawingArea widget, has a Gdk::GC variable, a colormap variable and a pixmap variable, and I am redrawing completely the pixmap at each on_expose_event. At first, I initialised my variables (the parent window, the gc, etc...) in the constructor fo my widget, but it failed miserabily, which seemed later logical, as the widget should be constructed before being used inside any parent widget. After that, I put 'randomly' the code into the on_configure_event, mainly because the configure word in the signal: I couldn't find any useful info about this signal in the examples or in the reference manual of gtkmm.

In the gtk vumeter of alsaplayer, it seems like the gc, pixmap are created in the 'constructor', that is, the code is called only once. It seems stupid to me to call Gdk::GC::create in a function which is often called. I should need to call Gdk::GC::create once, shouldn't I ?

Is there any informations on these technical points ? These don't seem to be covered in the official gtkmm tutorial, and the reference is not deep enough for me, as I don't have much experience on GUI concepts like graphic context and so on... Should I study gtk and gdk before using gtkmm ( ardour, which is the only gtkmm audio program I know, seems to call directly gtk and gdk functions, and is written with the 1.2 gtkmm anyway, which seems really different from the 2.* version, particularly concerning memory management techniques like smart pointers) ?

   Thanks a lot, and my apologies for my long and no very clear email,

   Cheers,

   David

PS: putting the code of my widget may be clearer than my painful explanations

vuMeter.h:

#ifndef _VUMETER_CLASS_HEADER_
#define _VUMETER_CLASS_HEADER_
#include <gtkmm.h>

#define SCOPE_BG_RED 0
#define SCOPE_BG_BLUE 0
#define SCOPE_BG_GREEN 0
class vuMeter : public Gtk::DrawingArea
{
public:
   vuMeter(int x , int y );
   virtual ~vuMeter();
protected:
   bool on_expose_event(GdkEventExpose* event);
   bool on_configure_event(GdkEventConfigure*);
protected:
   Glib::RefPtr<Gdk::GC>       m_gc;
   Glib::RefPtr<Gdk::Pixmap>   m_disp;
   Glib::RefPtr<Gdk::Window>   m_win;
   Glib::RefPtr<Gdk::Colormap> m_colormap;
   Gdk::Color                  m_dispColor;
};
#endif

File vuMeter.cpp :

#include <iostream>

#include "vuMeter.h"

vuMeter::vuMeter(int x , int y )
   : DrawingArea()
{
   std::cout << "Beginning of vumeter construction...\n";
   set_size_request(x,y);
   init();
}

vuMeter::~vuMeter()
{
}

bool vuMeter::on_expose_event(GdkEventExpose *)
{
   std::cout << "on_expose called\n" ;
// Set the background to black
   Glib::RefPtr<Gtk::Style>    curStyle = get_style();
   m_gc -> set_foreground(curStyle->get_black());
   m_disp->draw_rectangle(m_gc, TRUE, 0, 0, 256, 18);

   // Draw the disp
   int i;

   for (i = 0; i < 256; i+=4)
   {
if (i < 128) { m_dispColor.set_red( (i<<1) << 8);
       m_dispColor.set_green( 255  << 8);
       m_dispColor.set_blue( 0);
   }
       else {
       m_dispColor.set_red( 255 << 8);
       m_dispColor.set_green( (255 - (i << 1)) << 8);
       m_dispColor.set_blue (0);
} m_colormap->alloc_color(m_dispColor);
   m_gc->set_foreground(m_dispColor);
   m_disp->draw_line(m_gc,i,0,i,18);
   m_disp->draw_line(m_gc,i+1,0,i+1,18);
   m_disp->draw_line(m_gc,i+2,0,i+2,18);
   }

   m_win->draw_drawable(m_gc, m_disp, 0, 0, 0, 0);
return true;
}

bool vuMeter::on_configure_event(GdkEventConfigure*)
{
   std::cout << "on_configure_event called\n" ;
   // Get the current colormap
   m_colormap = Gdk::Colormap::create (Gdk::Visual::get_system(),
           TRUE);

   // m_win is a RefPtr to the parent window of the widget
   m_win = get_window();
// set the gc
   m_gc = Gdk::GC::create(m_win);
// Create m_disp
   m_disp = Gdk::Pixmap::create(m_win, 256, 18,
               Gdk::Visual::get_best_depth());

   return true;
}




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]