如何使用 gtk c 更改 "gdk_pixbuf_composite" 中的选择形状标记?
How to change selection shape marker in "gdk_pixbuf_composite" with gtk c?
我使用此代码进行作物选择:
gboolean mouse_press_callback(GtkWidget *event_box,
GdkEventButton *event,
gpointer data)
{
if (img1buffer == NULL)
return TRUE;
static gint press_x = 0, press_y = 0, rel_x = 0, rel_y = 0;
GtkAllocation ebox;
gint img1_x_offset = 0, img1_y_offset = 0;
gtk_widget_get_allocation(event_box, &ebox);
img1_x_offset = (ebox.width - width) / 2;
img1_y_offset = (ebox.height - height) / 2;
if (event->type == GDK_BUTTON_PRESS)
{
press_x = event->x - img1_x_offset;
press_y = event->y - img1_y_offset;
//g_print ("Event box clicked at coordinates %f,%f\n",
//event->x - img1_x_offset, event->y - img1_y_offset);
}
else if (event->type == GDK_BUTTON_RELEASE)
{
rel_x = event->x - img1_x_offset;
rel_y = event->y - img1_y_offset;
//g_print ("Event box released at coordinates %f,%f\n",
//event->x - img1_x_offset, event->y - img1_y_offset);
dest_x = rel_x < press_x ? rel_x : press_x;
dest_y = rel_y < press_y ? rel_y : press_y;
dest_width = abs(rel_x - press_x);
dest_height = abs(rel_y - press_y);
// mark user selection in image
GdkPixbuf *img1buffer_resized = gdk_pixbuf_scale_simple(img1buffer, width, height, GDK_INTERP_TILES);
gdk_pixbuf_composite(croppic, img1buffer_resized, dest_x, dest_y, dest_width, dest_height, 0, 0, 1, 1, GDK_INTERP_TILES, 170);
gtk_image_set_from_pixbuf(GTK_IMAGE(img1), img1buffer_resized);
}
return TRUE;
}
主函数中的那个:
croppic = gdk_pixbuf_new_from_file("E:/Works for Gov Project/DOC/GUI/logogui1/crop_bg.png", NULL);
img1 = gtk_image_new();
event_box = gtk_event_box_new();
gtk_event_box_set_visible_window(GTK_EVENT_BOX(event_box), FALSE);
gtk_container_add(GTK_CONTAINER(event_box), img1);
gtk_container_add(GTK_CONTAINER(frame1), event_box);
g_signal_connect(G_OBJECT(event_box), "button_press_event", G_CALLBACK(mouse_press_callback), NULL);
g_signal_connect(G_OBJECT(event_box), "button-release-event", G_CALLBACK(mouse_press_callback), NULL);
和"crop_bg.png"是:
但是我想要一个类似于画图软件的选区形状:
对于如何解决这个任务,您有什么建议?或者我可以在互联网上的哪些资源上找到帮助?
您正在尝试在 GtkImage 上绘图。这不是进行自定义绘图的最佳方式,正如您所注意到的,gdk_pixbuf_composite()
相当有限。
相反,您需要使用 ::draw
信号和开罗来绘制 the proper way。 cairo 是 GTK+ 3 用来绘制自己的小部件的矢量图形库,::draw
信号为您提供了一个 cairo 上下文来绘制:
gboolean draw(GtkWidget *widget, cairo_t *cr, void *data);
cairo 本身很容易使用;是 well documented and has a whole bunch of samples。您想为您的目的做的是制作一个虚线描边矩形。
此外,您需要使用 GtkDrawingArea 而不是 GtkImage。 GtkDrawingArea 是专门为绘制而设计的,只需做一些额外的工作就可以处理您的事件。
那么最后一块拼图是当鼠标事件进来时如何开始绘图?你没有在 button-press-event
或 button-release-event
中得到 cairo_t
,所以你不能在那里画画。事实上,GTK+ 已经过优化,因此它只在必要时绘制。要表示需要绘制,可以使用 gtk_widget_queue_draw()
方法。此方法有一些变体,仅标记要重绘的小部件的一个子集(您可以从 ::draw
处理程序中使用 cairo_clip_extents()
取回该子集)。
请记住小部件坐标是浮点数;开罗坐标也是。
我们来演示一下。我将为此使用全局变量;你可能不想。
gdouble x0, y0;
gdouble x1, y1;
这些将存储矩形的端点。当我们按下鼠标键时,我们要开始绘图:
gboolean button_press_event(GtkWidget *widget, GdkEventButton *e, gpointer data)
{
// ...
x0 = e->x;
y0 = e->y;
x1 = e->x; // start with a zero-sized rectangle
y1 = e->y;
// ...
}
当我们移动鼠标时,我们要将x1
和y1
更改为新的鼠标坐标,然后更新矩形。为了优化,我们只会更新发生变化的区域:
gboolean motion_notify_event(GtkWidget *widget, GdkEventMotion *e, gpointer data)
{
// ...
// first queue both old and new rectangles for drawing
gtk_widget_queue_draw_area(widget,
x0, y0,
MAX(x1, e->x), MAX(y1, e->y));
// then set the new rectangle
x1 = e->x;
y1 = e->y;
// ...
}
您大概可以从上面的内容中了解在 button-release-event
上要做什么。 draw
看起来像
gboolean draw(GtkWidget *widget, cairo_t *cr, gpointer data)
{
// ...
cairo_rectangle(cr, x0, y0, x1 - x0, y1 - y0);
// set up a dashed solid-color stroke
cairo_stroke(cr);
// ...
}
祝你好运!
我使用此代码进行作物选择:
gboolean mouse_press_callback(GtkWidget *event_box,
GdkEventButton *event,
gpointer data)
{
if (img1buffer == NULL)
return TRUE;
static gint press_x = 0, press_y = 0, rel_x = 0, rel_y = 0;
GtkAllocation ebox;
gint img1_x_offset = 0, img1_y_offset = 0;
gtk_widget_get_allocation(event_box, &ebox);
img1_x_offset = (ebox.width - width) / 2;
img1_y_offset = (ebox.height - height) / 2;
if (event->type == GDK_BUTTON_PRESS)
{
press_x = event->x - img1_x_offset;
press_y = event->y - img1_y_offset;
//g_print ("Event box clicked at coordinates %f,%f\n",
//event->x - img1_x_offset, event->y - img1_y_offset);
}
else if (event->type == GDK_BUTTON_RELEASE)
{
rel_x = event->x - img1_x_offset;
rel_y = event->y - img1_y_offset;
//g_print ("Event box released at coordinates %f,%f\n",
//event->x - img1_x_offset, event->y - img1_y_offset);
dest_x = rel_x < press_x ? rel_x : press_x;
dest_y = rel_y < press_y ? rel_y : press_y;
dest_width = abs(rel_x - press_x);
dest_height = abs(rel_y - press_y);
// mark user selection in image
GdkPixbuf *img1buffer_resized = gdk_pixbuf_scale_simple(img1buffer, width, height, GDK_INTERP_TILES);
gdk_pixbuf_composite(croppic, img1buffer_resized, dest_x, dest_y, dest_width, dest_height, 0, 0, 1, 1, GDK_INTERP_TILES, 170);
gtk_image_set_from_pixbuf(GTK_IMAGE(img1), img1buffer_resized);
}
return TRUE;
}
主函数中的那个:
croppic = gdk_pixbuf_new_from_file("E:/Works for Gov Project/DOC/GUI/logogui1/crop_bg.png", NULL);
img1 = gtk_image_new();
event_box = gtk_event_box_new();
gtk_event_box_set_visible_window(GTK_EVENT_BOX(event_box), FALSE);
gtk_container_add(GTK_CONTAINER(event_box), img1);
gtk_container_add(GTK_CONTAINER(frame1), event_box);
g_signal_connect(G_OBJECT(event_box), "button_press_event", G_CALLBACK(mouse_press_callback), NULL);
g_signal_connect(G_OBJECT(event_box), "button-release-event", G_CALLBACK(mouse_press_callback), NULL);
和"crop_bg.png"是:
但是我想要一个类似于画图软件的选区形状:
对于如何解决这个任务,您有什么建议?或者我可以在互联网上的哪些资源上找到帮助?
您正在尝试在 GtkImage 上绘图。这不是进行自定义绘图的最佳方式,正如您所注意到的,gdk_pixbuf_composite()
相当有限。
相反,您需要使用 ::draw
信号和开罗来绘制 the proper way。 cairo 是 GTK+ 3 用来绘制自己的小部件的矢量图形库,::draw
信号为您提供了一个 cairo 上下文来绘制:
gboolean draw(GtkWidget *widget, cairo_t *cr, void *data);
cairo 本身很容易使用;是 well documented and has a whole bunch of samples。您想为您的目的做的是制作一个虚线描边矩形。
此外,您需要使用 GtkDrawingArea 而不是 GtkImage。 GtkDrawingArea 是专门为绘制而设计的,只需做一些额外的工作就可以处理您的事件。
那么最后一块拼图是当鼠标事件进来时如何开始绘图?你没有在 button-press-event
或 button-release-event
中得到 cairo_t
,所以你不能在那里画画。事实上,GTK+ 已经过优化,因此它只在必要时绘制。要表示需要绘制,可以使用 gtk_widget_queue_draw()
方法。此方法有一些变体,仅标记要重绘的小部件的一个子集(您可以从 ::draw
处理程序中使用 cairo_clip_extents()
取回该子集)。
请记住小部件坐标是浮点数;开罗坐标也是。
我们来演示一下。我将为此使用全局变量;你可能不想。
gdouble x0, y0;
gdouble x1, y1;
这些将存储矩形的端点。当我们按下鼠标键时,我们要开始绘图:
gboolean button_press_event(GtkWidget *widget, GdkEventButton *e, gpointer data)
{
// ...
x0 = e->x;
y0 = e->y;
x1 = e->x; // start with a zero-sized rectangle
y1 = e->y;
// ...
}
当我们移动鼠标时,我们要将x1
和y1
更改为新的鼠标坐标,然后更新矩形。为了优化,我们只会更新发生变化的区域:
gboolean motion_notify_event(GtkWidget *widget, GdkEventMotion *e, gpointer data)
{
// ...
// first queue both old and new rectangles for drawing
gtk_widget_queue_draw_area(widget,
x0, y0,
MAX(x1, e->x), MAX(y1, e->y));
// then set the new rectangle
x1 = e->x;
y1 = e->y;
// ...
}
您大概可以从上面的内容中了解在 button-release-event
上要做什么。 draw
看起来像
gboolean draw(GtkWidget *widget, cairo_t *cr, gpointer data)
{
// ...
cairo_rectangle(cr, x0, y0, x1 - x0, y1 - y0);
// set up a dashed solid-color stroke
cairo_stroke(cr);
// ...
}
祝你好运!