0

I want to use expose-event to draw something then update or redraw. That's to say, there are a drawing area and a button in window. When clicking button, the drawing area will be redrawn accordingly. My problems are

  1. In the following code, if I changed gtk_container_add (GTK_CONTAINER (box), canvas); to gtk_box_pack_start(GTK_BOX(box), canvas, FALSE, FALSE, 0);, nothing is drawn. Usually we use gtk_box_pack_start to add something into box. Why doesn't it work this time?

  2. The function build_ACC_axis refreshed(deleted what has drawn) drawing area and prepared for new draw. But it didn't delete what has drawn. Why? How to refresh the drawing area?

If the source file is test.c, then compilation is

gcc -o test test.c `pkg-config --cflags --libs gtk+-2.0`

The code is below:

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

static void draw (GdkDrawable *d, GdkGC *gc)
{
  /* Draw with GDK */
  gdk_draw_line (d, gc, 0, 0, 50, 50);
  gdk_draw_line (d, gc, 50, 50, 50, 150);
  gdk_draw_line (d, gc, 50, 150, 0, 200);

  gdk_draw_line (d, gc, 200, 0, 150, 50);
  gdk_draw_line (d, gc, 150, 50, 150, 150);
  gdk_draw_line (d, gc, 150, 150, 200, 200);

  gdk_draw_line (d, gc, 50, 50, 150, 50);
  gdk_draw_line (d, gc, 50, 150, 150, 150);
}

static gboolean expose_cb (GtkWidget *canvas, GdkEventExpose *event, gpointer user_data)
{
  GdkGC *gc;

  gc = gdk_gc_new (canvas->window);
  draw (canvas->window, gc);
  g_object_unref (gc);

  return FALSE;
}

void build_ACC_axis (GtkWidget *button, GtkWidget *widget)
{
  GdkRegion *region;

  GtkWidget *canvas = g_object_get_data(G_OBJECT(widget), "plat_GA_canvas");

  region = gdk_drawable_get_visible_region(canvas->window);
  gdk_window_invalidate_region(canvas->window, region, TRUE);
  gtk_widget_queue_draw(canvas);
  /* gdk_window_process_updates(canvas->window, TRUE); */
  gdk_region_destroy (region);
}

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

  gtk_init (&argc, &argv);

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_widget_set_size_request(window, 500, 300);
  g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (gtk_main_quit), NULL);

  box = gtk_vbox_new(FALSE, 0);
  gtk_container_add (GTK_CONTAINER (window), box);

  canvas = gtk_drawing_area_new ();
  g_object_set_data(G_OBJECT(window), "plat_GA_canvas", canvas);
  /* gtk_box_pack_start(GTK_BOX(box), canvas, FALSE, FALSE, 0); */
  gtk_container_add (GTK_CONTAINER (box), canvas);
  g_signal_connect (G_OBJECT (canvas), "expose-event", G_CALLBACK (expose_cb), NULL);

  button = gtk_button_new_with_label ("ok");
  gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0);
  /* gtk_container_add (GTK_CONTAINER (box), button); */
  gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(build_ACC_axis), window);

  gtk_widget_show_all (window);

  gtk_main ();
}

I would like to answer my second question. After clicking button, it would send expose-event signal and run expose_cb. Since there is no change in draw function, we can't see the refreshing. Following is the updated code that can show refreshing. The point is to add variable factor. But for the first question, I still didn't know why.

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

int factor;
static void draw (GdkDrawable *d, GdkGC *gc, double fac)
{
  /* Draw with GDK */
  gdk_draw_line (d, gc, 0, 0, 50, 50 * fac);
  gdk_draw_line (d, gc, 50, 50, 50, 150);
  gdk_draw_line (d, gc, 50, 150, 0, 200);

  gdk_draw_line (d, gc, 200, 0, 150, 50);
  gdk_draw_line (d, gc, 150, 50, 150, 150);
  gdk_draw_line (d, gc, 150, 150, 200, 200);

  gdk_draw_line (d, gc, 50, 50, 150, 50);
  gdk_draw_line (d, gc, 50, 150, 150, 150);
}

static gboolean expose_cb (GtkWidget *canvas, GdkEventExpose *event, gpointer user_data)
{
  GdkGC *gc;

  gc = gdk_gc_new (canvas->window);
  draw (canvas->window, gc, factor);
  g_object_unref (gc);

  return FALSE;
}

void build_ACC_axis (GtkWidget *button, GtkWidget *widget)
{
  GdkRegion *region;

  GtkWidget *canvas = g_object_get_data(G_OBJECT(widget), "plat_GA_canvas");

  region = gdk_drawable_get_visible_region(canvas->window);
  gdk_window_invalidate_region(canvas->window, region, TRUE);
  /* gtk_widget_queue_draw(canvas); */
  gdk_window_process_updates(canvas->window, TRUE);
  gdk_region_destroy (region);
  factor++;

}

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

  gtk_init (&argc, &argv);

  factor = 1;
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_widget_set_size_request(window, 500, 300);
  g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (gtk_main_quit), NULL);

  box = gtk_vbox_new(FALSE, 0);
  gtk_container_add (GTK_CONTAINER (window), box);

  canvas = gtk_drawing_area_new ();
  g_object_set_data(G_OBJECT(window), "plat_GA_canvas", canvas);
  /* gtk_box_pack_start(GTK_BOX(box), canvas, FALSE, FALSE, 0); */
  gtk_container_add (GTK_CONTAINER (box), canvas);
  g_signal_connect (G_OBJECT (canvas), "expose-event", G_CALLBACK (expose_cb), NULL);

  button = gtk_button_new_with_label ("ok");
  gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0);
  /* gtk_container_add (GTK_CONTAINER (box), button); */
  gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(build_ACC_axis), window);

  gtk_widget_show_all (window);

  gtk_main ();
}
warem
  • 1,471
  • 2
  • 14
  • 21
  • You need to set some initial size for the drawing area, try adding `gtk_widget_set_size_request(canvas, 200, 200);` after you create the drawing area widget. To clear contents of `GdkWindow` you can make use of `gdk_window_clear` but seem have figured out what was happening anyway – another.anon.coward Jul 06 '12 at 15:50

0 Answers0