您的位置:首页 > 其它

关于drawing_area绘图区的显示问题

2011-11-11 09:55 357 查看
关键词: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_LE***E_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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: