R. Lambert
R. Lambert

Reputation: 9

Is it possible to draw GTK widgets on a GTK drawing area, then update the graphics?

Suppose I draw a line diagram of, in my case, a model train layout. I can change the colors of the various drawing components when I update the drawing, for example indicating an alarm condition. I would like to add several "switch" widgets, "toggle" buttons, etc. to the diagram so I can toggle electrical items on/off with my Raspberry Pi (inspired by industrial process control). Is this possible? ...or is there a better way?

A different way, but not as good, is to display a GtkImage graphic in a good ol' generic window, then install widgets atop the graphic. This works but you can’t change the colors of the individual drawing components, the way you can in a Drawing_Area widget. In order to change the graphic, you have to do a screen capture, then crop the image, then save the image as a JPEG of proper size, then update the GtkImage somehow.

Displaying widgets on the Drawing_Area would be far better. …any ideas?

Upvotes: 1

Views: 1120

Answers (2)

R. Lambert
R. Lambert

Reputation: 9

It turns out that, in GLADE, if you use a GtkWindow widget and insert a GtkFixed widget in it, then insert a GtkDrawingArea in there too, you can both write and draw. I use this to install other widgets provided by GLADE, then draw diagrams via program code. I can alter the widgets via code, as in the following which changes the color of a label widget. I click on the label to change a relay's state.

`dir_label=gap_ptr_array.label_ptr[i];
 state=gtk_label_get_text(gap_ptr_array.label_ptr[i]); 
 this_pwr_code=display_data[i].block_pwr;
 if(this_pwr_code!=0)
 { format="<span foreground=\"#eeeeee\">%s</span>"; 
   markup=g_markup_printf_escaped(format,state);
   format_bkgnd="<span background=\"#00ff00\">%s</span>"; // green
   markup_bkgnd=g_markup_printf_escaped(format_bkgnd,state);
   gtk_label_set_text( dir_label, state);
   gtk_label_set_markup(dir_label, markup);
   gtk_label_set_markup(dir_label, markup_bkgnd);
 }
 else
 { format="<span foreground=\"#eeeeee\">%s</span>"; 
   markup=g_markup_printf_escaped(format,state);
   format_bkgnd="<span background=\"#990000\">%s</span>"; // red
   markup_bkgnd=g_markup_printf_escaped(format_bkgnd,state);
   gtk_label_set_text( dir_label, state);
   gtk_label_set_markup(dir_label, markup);
   gtk_label_set_markup(dir_label, markup_bkgnd);
 }`

Then, I can use drawing commands to display a line diagram of the process I am controlling

cairo_save(cr);  // save the original scaling
cairo_scale(cr,global_width, global_height);
cairo_set_line_width(cr,0.01);
cairo_select_font_face(cr,"Purisa"
  ,CAIRO_FONT_SLANT_NORMAL,CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size(cr, 13);
// draw Block 08
set_block_color(cr,8);
cairo_arc (cr, 0.35, 0.38, 0.08, G_PI, 1.5 * G_PI); //  LHS yard upper corner
cairo_stroke(cr);
// draw Block 09
  ...etc...

Thus it is possible to use both pre-programmed GLADE widgets and code-based lettering/drawing code to get the display mix that you want. It's still a challenge to position your widgets and your drawn items properly, but it's very doable.

Upvotes: 0

GiuTor
GiuTor

Reputation: 111

Here you are mate. Better late than ever... ;)

#include <gtk/gtk.h>
#include <math.h>

GtkWidget *window;
GtkWidget *layout;
GtkWidget *canvas;

GtkWidget *image;
GtkWidget *eventbox;

static gboolean on_window_draw (GtkWidget *da, GdkEventExpose *event, gpointer data)
{
    GdkWindow *window;
    GdkDrawingContext *drawingContext;
    cairo_region_t *cairoRegion;
    cairo_t *cr;

    cairoRegion = cairo_region_create();
    window = gtk_layout_get_bin_window(GTK_LAYOUT(layout)); 
    drawingContext = gdk_window_begin_draw_frame(window, cairoRegion);
    cr = gdk_drawing_context_get_cairo_context(drawingContext);

    cairo_set_line_width(cr, 9);  
    cairo_set_source_rgb(cr, 0.69, 0.19, 0);

    cairo_translate(cr, 300/2, 200/2);
    cairo_arc(cr, 0, 0, 50, 0, 2 * M_PI);
    cairo_stroke_preserve(cr);

    cairo_set_source_rgb(cr, 0.3, 0.4, 0.6); 
    cairo_fill(cr);

    gdk_window_end_draw_frame(window, drawingContext);
    cairo_region_destroy(cairoRegion);

    return FALSE;
}

int main ( int argc, char **argv) 
{   
    GtkWidget *button;

    gtk_init (&argc , &argv);
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_widget_set_size_request (window, 300, 200);
    g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit) , NULL);

    canvas = gtk_drawing_area_new ();
    layout = gtk_layout_new(NULL,NULL);
    gtk_container_add (GTK_CONTAINER (layout), canvas);
    gtk_container_add (GTK_CONTAINER (window), layout);

    button = gtk_button_new_with_label("I feel alone...");
    gtk_container_add(GTK_CONTAINER(layout), button);
    gtk_layout_move(GTK_LAYOUT(layout), button, 90, 50);
    g_signal_connect (canvas, "draw", (GCallback) on_window_draw, NULL);

    gtk_widget_show_all (window);
    gtk_main ();
    return 0;
}

Upvotes: 0

Related Questions