如何使用 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-eventbutton-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;
    // ...
}

当我们移动鼠标时,我们要将x1y1更改为新的鼠标坐标,然后更新矩形。为了优化,我们只会更新发生变化的区域:

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);
    // ...
}

祝你好运!