如何用gtk c更改“gdk_pixbuf_composite”中的选择形状标记?

时间:2016-06-18 12:55:29

标签: gtk gtk3

我使用此代码进行裁剪选择:

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”是:

enter image description here

但我想要一个类似于绘画软件的选择形状:

enter image description here

您建议如何解决此任务的想法?或者我可以在互联网上的哪些资源上找到帮助?

1 个答案:

答案 0 :(得分:1)

您正试图在GtkImage上绘图。这不是进行自定义绘图的最佳方式,正如您所注意到的,gdk_pixbuf_composite()相当有限。

相反,您需要使用::draw信号和cairo绘制the proper way。 cairo是GTK + 3用来绘制自己的小部件的矢量图形库,::draw信号为你提供了一个绘制的cairo上下文:

gboolean draw(GtkWidget *widget, cairo_t *cr, void *data);

cairo本身很容易使用;它是well documented并且有a whole bunch of samples。你想要为你的目的做的是做一个虚线描边矩形。

此外,您不想使用GtkImage,而是使用GtkDrawingArea。 GtkDrawingArea专门设计用于绘制,并且可以通过一些额外的工作来处理您的活动。

最后一个难题是,当鼠标事件进入时你是如何开始绘画的?您未在cairo_tbutton-press-event中获得button-release-event,因此您无法在那里进行展示。实际上,GTK +已经过优化,只有在必要时才会绘制。为了表明有必要绘制,您可以使用gtk_widget_queue_draw()方法。此方法有一些变体,仅标记要重绘的窗口小部件的子集(您可以使用cairo_clip_extents()处理程序中的::draw返回此子集。

请记住,小部件坐标是浮点数; cairo坐标也是如此。

让我们来证明一下。我将为此使用全局变量;你可能不想这样做。

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);
    // ...
}
祝你好运!