关于drawing_area绘图区的显示问题

关于drawing_area绘图区的显示问题
http://hi.baidu.com/dalier/blog/item/20b0b101b830bbd7267fb50d.html

关键词:configure_event , expose_event , gtk_drawing_area_new , gdk_draw_drawable , gtk_widget_queue_draw_area , button-press-event ,
为了记住如何使用drawing_area,特意编写了一个小例子。

功能:
1.在绘图区上点击鼠标左键、中键和右键,可以画出不同的图形;
2.按“clear"按钮,可以重新绘制。比较简单,主要是用来演示如何在 drawing_area上绘制图形,
  注意在每次调用my_draw(..)之后是如何在绘图区上显示出来图形的。

/* eg_drawing_area.c */
#include <gtk/gtk.h>

static GdkPixmap *pixmap = NULL;
GdkGC *my_gc_red;
GdkColor color;

int my_configure_event(GtkWidget *widget , GdkEventConfigure *event){
    if(pixmap)
        g_object_unref(pixmap);
    pixmap = gdk_pixmap_new(widget->window, widget->allocation.width, widget->allocation.height, -1);
    gdk_draw_rectangle(pixmap , widget->style->white_gc ,
                  TRUE , 0 , 0 ,
                  widget->allocation.width ,
                  widget->allocation.height);

    my_gc_red = gdk_gc_new(widget->window);
    color.red = 30000;
    color.green = 0;
    color.blue = 30000;
    gdk_gc_set_rgb_fg_color(my_gc_red , &color);    

    return 0;
}

int my_expose_event(GtkWidget *widget , GdkEventExpose *event , gpointer data){
    gdk_draw_drawable(widget->window ,
              widget->style->fg_gc[GTK_WIDGET_STATE(widget)] ,
              pixmap , 0 , 0 , 0 , 0 ,
              widget->allocation.width ,
              widget->allocation.height);    

    return 0;
}

int my_draw(GtkWidget *widget , double x , double y , int type){
    switch(type){
        case 1:
            gdk_draw_rectangle(pixmap , widget->style->black_gc, FALSE, x, y, 10, 10);
            gtk_widget_queue_draw_area(widget, x, y, 10, 10);
            break;
        case 2:
            gdk_draw_rectangle(pixmap ,my_gc_red ,TRUE,x , y , 15 , 15);
            gtk_widget_queue_draw_area(widget ,x , y , 15 , 15);
            break;
        case 3:
            gdk_draw_line(pixmap , my_gc_red ,x , y , x + 15 , y - 15);
            gtk_widget_queue_draw_area(widget ,x , y - 15 , 15 , 15);
            break;
        default:
            printf("....\n");
            break;
    }
    return 0;
}

int my_button_press_event(GtkWidget *widget , GdkEventButton *event){
      my_draw(widget , event->x , event->y , event->button);    
      printf("x=%lf y=%lf\n" , event->x , event->y);
      return 0;    
}

int my_clear(GtkWidget *widget , GtkWidget *area){
      gdk_draw_rectangle(pixmap ,
              area->style->white_gc ,
              TRUE , 0 , 0 ,
              area->allocation.width ,
              area->allocation.height);
      gtk_widget_queue_draw(area);

      return 0;
}

int my_quit(GtkWidget *widget , gpointer data){
      gtk_main_quit();
      return 0;
}

int main(int argc , char *argv[]){
      GtkWidget *window;
      GtkWidget *drawing_area;
      GtkWidget *vbox;
      GtkWidget *bt_clear;
      GtkWidget *bt_quit;

      gtk_init(&argc , &argv);
    
      window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
      gtk_widget_set_name(window , "Test drawing_area");
      gtk_widget_set_size_request(window , 300 , 200);
      gtk_container_set_border_width(GTK_CONTAINER(window) , 2);
      gtk_window_set_resizable(GTK_WINDOW(window) , FALSE);

      vbox = gtk_vbox_new(FALSE , 0);
      gtk_container_add(GTK_CONTAINER(window) , vbox);
      gtk_widget_show(vbox);
    
      g_signal_connect(G_OBJECT(window) , "destroy" ,
              G_CALLBACK(my_quit) , NULL);

      drawing_area = gtk_drawing_area_new();
      gtk_box_pack_start(GTK_BOX(vbox) , drawing_area , TRUE , TRUE , 0);
      gtk_widget_show(drawing_area);
      g_signal_connect(G_OBJECT(drawing_area) , "configure_event" ,
              G_CALLBACK(my_configure_event) , NULL);
      g_signal_connect(G_OBJECT(drawing_area) , "expose_event" ,
              G_CALLBACK(my_expose_event) , NULL);
      g_signal_connect(G_OBJECT(drawing_area) , "button_press_event" ,
              G_CALLBACK(my_button_press_event) , NULL);
      gtk_widget_set_events(drawing_area , GDK_BUTTON_PRESS_MASK);
    
      bt_clear = gtk_button_new_with_label("clear");
      gtk_box_pack_start(GTK_BOX(vbox) , bt_clear , FALSE , FALSE , 0);
      g_signal_connect(G_OBJECT(bt_clear) , "clicked" ,
              G_CALLBACK(my_clear) , drawing_area);
      gtk_widget_show(bt_clear);
    
      bt_quit = gtk_button_new_with_label("quit");
      gtk_box_pack_start(GTK_BOX(vbox) , bt_quit , FALSE , FALSE , 0);
      g_signal_connect(G_OBJECT(bt_quit) , "clicked" ,
              G_CALLBACK(my_quit) , window);
      gtk_widget_show(bt_quit);

      gtk_widget_show(window);

      gtk_main();

      return 0;
}

简单的说,就是每次在pixmap上绘制,然后把pixmap贴到drawing_area上去。要点如下:

1.把pixmap贴到drawing_area的函数:
    gdk_draw_drawable(widget->window ,                      //目的地
        widget->style->fg_gc[GTK_WIDGET_STATE(widget)],        //剩余部分的填充方式
        pixmap ,                                            //源
        0 , 0 ,                                             //源的左上角坐标XY
        0 , 0 ,                                             //目的地的左上角坐标XY
        widget->allocation.width ,                          //取源的宽
        widget->allocation.height);                         //取源的高

2.显示drawing_area的特定区域:
    gtk_widget_queue_draw_area(widget , //这就是draw_area
        x , y ,                         //draw_area的要显示的矩形区域的左上角坐标XY
        15 , 15);                       //矩形区域的宽和高

3.显示drawing_area的全部区域:
    gtk_widget_queue_draw(widget);

4.为了演示方便,加入了鼠标的操作:

int my_button_press_event(GtkWidget *widget , GdkEventButton *event){
    //event->button的值1,2,3分别对应鼠标左键、中键、右键
      my_draw(widget , event->x , event->y , event->button);     
      printf("x=%lf y=%lf\n" , event->x , event->y);       //注意这里的x,y是double类型的
      return 0;    
}

另外要注意的是,若想捕获信号button-press-event的话,需要添加函数gtk_widget_set_events(drawing_area , GDK_BUTTON_PRESS_MASK)


有找到一篇类似的文章,注意在drawing_area上响应key_press_event的用法,
先获取焦点:
    GTK_WIDGET_SET_FLAGS (drawing_area, GTK_CAN_FOCUS);
    gtk_widget_grab_focus (drawing_area);

代码如下:

/* GTK - The GIMP Toolkit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.   See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/

/*
* Modified by the GTK+ Team and others 1997-2000.   See the AUTHORS
* file for a list of people on the GTK+ Team.   See the ChangeLog
* files for a list of changes.   These files are distributed with
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/

//#include <config.h>
#include <stdio.h>
#include "gtk/gtk.h"

/* Backing pixmap for drawing area */

static GdkPixmap *pixmap = NULL;

/* Information about cursor */

static gint cursor_proximity = TRUE;
static gdouble cursor_x;
static gdouble cursor_y;

/* Unique ID of current device */
static GdkDevice *current_device;

/* Erase the old cursor, and/or draw a new one, if necessary */
static void
update_cursor (GtkWidget *widget,   gdouble x, gdouble y)
{
   static gint cursor_present = 0;
   gint state = !current_device->has_cursor && cursor_proximity;

   if (pixmap != NULL)
     {
       if (cursor_present && (cursor_present != state ||
         x != cursor_x || y != cursor_y))
{
    gdk_draw_drawable (widget->window,
         widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
         pixmap,
         cursor_x - 5, cursor_y - 5,
         cursor_x - 5, cursor_y - 5,
         10, 10);
}

       cursor_present = state;
       cursor_x = x;
       cursor_y = y;

       if (cursor_present)
{
    gdk_draw_rectangle (widget->window,
          widget->style->black_gc,
          TRUE,
          cursor_x - 5, cursor_y -5,
          10, 10);
}
     }
}

/* Create a new backing pixmap of the appropriate size */
static gint
configure_event (GtkWidget *widget, GdkEventConfigure *event)
{
   if (pixmap)
     g_object_unref (pixmap);
   pixmap = gdk_pixmap_new(widget->window,
      widget->allocation.width,
      widget->allocation.height,
      -1);
   gdk_draw_rectangle (pixmap,
         widget->style->white_gc,
         TRUE,
         0, 0,
         widget->allocation.width,
         widget->allocation.height);

   return TRUE;
}

/* Refill the screen from the backing pixmap */
static gint
expose_event (GtkWidget *widget, GdkEventExpose *event)
{
   gdk_draw_drawable (widget->window,
        widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
        pixmap,
        event->area.x, event->area.y,
        event->area.x, event->area.y,
        event->area.width, event->area.height);

   return FALSE;
}

/* Draw a rectangle on the screen, size depending on pressure,
    and color on the type of device */
static void
draw_brush (GtkWidget *widget, GdkInputSource source,
      gdouble x, gdouble y, gdouble pressure)
{
   GdkGC *gc;
   GdkRectangle update_rect;

   switch (source)
     {
     case GDK_SOURCE_MOUSE:
       gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)];
       break;
     case GDK_SOURCE_PEN:
       gc = widget->style->black_gc;
       break;
     case GDK_SOURCE_ERASER:
       gc = widget->style->white_gc;
       break;
     default:
       gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)];
     }

   update_rect.x = x - 10 * pressure;
   update_rect.y = y - 10 * pressure;
   update_rect.width = 20 * pressure;
   update_rect.height = 20 * pressure;
   gdk_draw_rectangle (pixmap, gc, TRUE,
         update_rect.x, update_rect.y,
         update_rect.width, update_rect.height);
   gtk_widget_queue_draw_area (widget,
          update_rect.x, update_rect.y,
          update_rect.width, update_rect.height);
   gdk_window_process_updates (widget->window, TRUE);
}

static guint32 motion_time;

static void
print_axes (GdkDevice *device, gdouble *axes)
{
   int i;
 
   if (axes)
     {
       g_print ("%s ", device->name);
      
       for (i=0; i<device->num_axes; i++)
g_print ("%g ", axes[i]);

       g_print ("\n");
     }
}

static gint
button_press_event (GtkWidget *widget, GdkEventButton *event)
{
   current_device = event->device;
   cursor_proximity = TRUE;

   if (event->button == 1 && pixmap != NULL)
     {
       gdouble pressure = 0.5;

       print_axes (event->device, event->axes);
       gdk_event_get_axis ((GdkEvent *)event, GDK_AXIS_PRESSURE, &pressure);
       draw_brush (widget, event->device->source, event->x, event->y, pressure);
      
       motion_time = event->time;
     }

   update_cursor (widget, event->x, event->y);

   return TRUE;
}

static gint
key_press_event (GtkWidget *widget, GdkEventKey *event)
{
   if ((event->keyval >= 0x20) && (event->keyval <= 0xFF))
     printf("I got a %c\n", event->keyval);
   else
     printf("I got some other key\n");

   return TRUE;
}

static gint
motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
{
   GdkTimeCoord **events;
   int n_events;
   int i;

   current_device = event->device;
   cursor_proximity = TRUE;

   if (event->state & GDK_BUTTON1_MASK && pixmap != NULL)
     {
       if (gdk_device_get_history (event->device, event->window,
       motion_time, event->time,
       &events, &n_events))
{
    for (i=0; i<n_events; i++)
      {
        double x = 0, y = 0, pressure = 0.5;

        gdk_device_get_axis (event->device, events[i]->axes, GDK_AXIS_X, &x);
        gdk_device_get_axis (event->device, events[i]->axes, GDK_AXIS_Y, &y);
        gdk_device_get_axis (event->device, events[i]->axes, GDK_AXIS_PRESSURE, &pressure);
        draw_brush (widget,   event->device->source, x, y, pressure);

        print_axes (event->device, events[i]->axes);
      }
    gdk_device_free_history (events, n_events);
}
       else
{
    double pressure = 0.5;

    gdk_event_get_axis ((GdkEvent *)event, GDK_AXIS_PRESSURE, &pressure);

    draw_brush (widget,   event->device->source, event->x, event->y, pressure);
}
       motion_time = event->time;
     }

   if (event->is_hint)
     gdk_device_get_state (event->device, event->window, NULL, NULL);

   print_axes (event->device, event->axes);
   update_cursor (widget, event->x, event->y);

   return TRUE;
}

/* We track the next two events to know when we need to draw a
    cursor */

static gint
proximity_out_event (GtkWidget *widget, GdkEventProximity *event)
{
   cursor_proximity = FALSE;
   update_cursor (widget, cursor_x, cursor_y);
   return TRUE;
}

static gint
leave_notify_event (GtkWidget *widget, GdkEventCrossing *event)
{
   cursor_proximity = FALSE;
   update_cursor (widget, cursor_x, cursor_y);
   return TRUE;
}

void
input_dialog_destroy (GtkWidget *w, gpointer data)
{
   *((GtkWidget **)data) = NULL;
}

void
create_input_dialog (void)
{
   static GtkWidget *inputd = NULL;

   if (!inputd)
     {
       inputd = gtk_input_dialog_new ();

       g_signal_connect (inputd, "destroy",
    G_CALLBACK (input_dialog_destroy), &inputd);
       g_signal_connect_swapped (GTK_INPUT_DIALOG (inputd)->close_button,
            "clicked",
            G_CALLBACK (gtk_widget_hide),
            inputd);
       gtk_widget_hide (GTK_INPUT_DIALOG (inputd)->save_button);

       gtk_widget_show (inputd);
     }
   else
     {
       if (!GTK_WIDGET_MAPPED(inputd))
gtk_widget_show(inputd);
       else
gdk_window_raise(inputd->window);
     }
}

void
quit (void)
{
   gtk_main_quit ();
}

int
main (int argc, char *argv[])
{
   GtkWidget *window;
   GtkWidget *drawing_area;
   GtkWidget *vbox;

   GtkWidget *button;

   gtk_init (&argc, &argv);

   current_device = gdk_device_get_core_pointer ();

   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
   gtk_widget_set_name (window, "Test Input");

   vbox = gtk_vbox_new (FALSE, 0);
   gtk_container_add (GTK_CONTAINER (window), vbox);
   gtk_widget_show (vbox);

   g_signal_connect (window, "destroy",
       G_CALLBACK (quit), NULL);

   /* Create the drawing area */

   drawing_area = gtk_drawing_area_new ();
   gtk_widget_set_size_request (drawing_area, 200, 200);
   gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);

   gtk_widget_show (drawing_area);

   /* Signals used to handle backing pixmap */

   g_signal_connect (drawing_area, "expose_event",
       G_CALLBACK (expose_event), NULL);
   g_signal_connect (drawing_area, "configure_event",
       G_CALLBACK (configure_event), NULL);

   /* Event signals */

   g_signal_connect (drawing_area, "motion_notify_event",
       G_CALLBACK (motion_notify_event), NULL);
   g_signal_connect (drawing_area, "button_press_event",
       G_CALLBACK (button_press_event), NULL);
   g_signal_connect (drawing_area, "key_press_event",
       G_CALLBACK (key_press_event), NULL);

   g_signal_connect (drawing_area, "leave_notify_event",
       G_CALLBACK (leave_notify_event), NULL);
   g_signal_connect (drawing_area, "proximity_out_event",
       G_CALLBACK (proximity_out_event), NULL);

   gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
     | GDK_LEAVE_NOTIFY_MASK
     | GDK_BUTTON_PRESS_MASK
     | GDK_KEY_PRESS_MASK
     | GDK_POINTER_MOTION_MASK
     | GDK_POINTER_MOTION_HINT_MASK
     | GDK_PROXIMITY_OUT_MASK);

   /* The following call enables tracking and processing of extension
      events for the drawing area */
   gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_ALL);

   GTK_WIDGET_SET_FLAGS (drawing_area, GTK_CAN_FOCUS);
   gtk_widget_grab_focus (drawing_area);

   /* .. And create some buttons */
   button = gtk_button_new_with_label ("Input Dialog");
   gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);

   g_signal_connect (button, "clicked",
       G_CALLBACK (create_input_dialog), NULL);
   gtk_widget_show (button);

   button = gtk_button_new_with_label ("Quit");
   gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);

   g_signal_connect_swapped (button, "clicked",
        G_CALLBACK (gtk_widget_destroy),
        window);
   gtk_widget_show (button);

   gtk_widget_show (window);

   gtk_main ();

   return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值