【问题标题】:Drawing lines with GTK+ and Cairo without removing what is already drawn使用 GTK+ 和 Cairo 绘制线条而不删除已绘制的内容
【发布时间】:2016-03-12 06:02:37
【问题描述】:

目前我正在用 C 语言编写一个程序,在一个 Linux 系统(确切地说是 Raspberry Pi)上,它应该使用 Cairo 绘制到 GTK 窗口。我一直在关注以下教程:http://zetcode.com/gfx/cairo/。但它在某些方面的解释含糊不清。

没有说明我真正需要的两点:

  1. 我不知道如何通过适当的函数调用绘制到窗口。
  2. 它会删除已绘制的内容。

我需要一段以非常面向对象的方式做一些简单事情的代码:

  1. 使用函数调用在 GTK 窗口中画线,给定起点和终点的 X 和 Y;
  2. 不要删除之前绘制的内容;
  3. 变量和窗口的所有初始化都应该在主函数之外。

所以基本上是这样的:

#include <cairo.h>
#include <gtk/gtk.h>

void drawLine(int xStart, int yStart, int yEnd, int xEnd) {
    //Drawing code here.
}

void initializeCairo() {
    //Insert cairo initialization.
}

void initializeGTK() {
    //Insert GTK initialization.
}

/*If needed a general initializer for both cairo and GTK*/
void initialize() {
    //Insert general initialization.
}

int main (int argc, char *archv[]) {
    intializeGTK();
    initializeCairo();
    if(doSomething) {
        drawLine(10, 10, 20, 20);
    }
}

如果可以解释一个方法的作用(请用正确的英语,而不是参考文档),那绝对很棒。

还请包括使用的 gcc 构建命令。

提前致谢!

【问题讨论】:

  • GTK+的绘图模型是“当需要重绘时,GtkWidget会通过发出draw信号通知你;在这个信号发出之前,它会清除widget给你一张白纸借鉴”。如果您想保留绘图区域的内容,您将需要以某种方式自己执行此操作(可能通过保存绘图参数;在您的情况下是线条列表)。您不能立即强制重绘,但您可以使用gtk_widget_queue_draw() 方法及其变体告诉 GTK+ 您想要重绘;然后,GTK+ 会在下次可以时给你draw 信号。
  • 这个绘图模型的价值不是 GTK+ 独有的;大多数 GUI 工具包和操作系统 API 都是这样工作的。如果您想了解更多信息,GTK+ 3 文档有更多关于自定义绘图的信息。尤其要注意剪裁的一些细节;如果 GTK+ 只需要更新小部件的一部分,它不会重绘所有内容
  • 感谢您提供的信息和实验室,这为我解决了一些问题。

标签: c linux gtk gtk3 cairo


【解决方案1】:

andlabs 的答案很好。这里还有一个简短的(虽然不完全优雅)的例子。它会“记住”最后的NUM 行 - 窗口的创建/调整大小/激活/停用将触发内容的“绘制”。单击下一步按钮将在输出中添加一个新行。还要检查命令行输出以获取更新 绘制的数组值。

#include <gtk/gtk.h>
#include <glib/gprintf.h>
#include <cairo.h>
#include <math.h>
#include <stdio.h>
#include <string.h>

#define NUM 3

typedef struct {
    GtkApplication *app;
    GtkWidget *window;
    GtkWidget *button;
    GtkWidget *da;
    cairo_t* cr;
    gboolean redraw;
    gint xsize;
    gint ysize;
} appWidgets;

gboolean drawEvent (GSimpleAction *action, GVariant *parameter, gpointer data);
void nextCallback (GtkWidget *widget, gpointer data);

void nextCallback (GtkWidget *widget, gpointer data)
{
    appWidgets *w = (appWidgets*) data;

    static gint cnt = 0;
    static gdouble x[NUM], y[NUM], u[NUM], v[NUM];

    // determine the next coordinates for a line
    if (w->redraw == FALSE) {
        x[cnt] = g_random_double();
        y[cnt] = g_random_double();
        u[cnt] = g_random_double();
        v[cnt] = g_random_double();
    }
    w->cr = gdk_cairo_create (gtk_widget_get_window (w->da));
    // map (0,0)...(xsize,ysize) to (0,0)...(1,1)
    cairo_translate (w->cr, 0, 0);
    cairo_scale (w->cr, w->xsize, w->ysize);
    // set linewidth
    cairo_set_line_width (w->cr, 0.005);
    // draw the lines
    for (int k = 0; k < NUM; k++) {
        cairo_move_to (w->cr, x[k], y[k]);
        cairo_line_to (w->cr, u[k], v[k]);
        cairo_stroke (w->cr);
        g_print("k=%d:(%1.2lf,%1.2lf).(%1.2lf,%1.2lf) ", 
            k, x[k], y[k], u[k], v[k]);
    }
    g_print("\n");
    cairo_destroy (w->cr);
    if (w->redraw == FALSE) {
        cnt++;
        if (cnt == NUM)
            cnt = 0;
    }
}

gboolean drawEvent (GSimpleAction *action, GVariant *parameter, gpointer data)
{
    appWidgets *w = (appWidgets*) data;

    w->xsize = gtk_widget_get_allocated_width (w->da);
    w->ysize = gtk_widget_get_allocated_height (w->da);
    w->redraw = TRUE;
    nextCallback (NULL, w);
    w->redraw = FALSE;
    return TRUE;
}

void activate (GtkApplication *app, gpointer data)
{
    GtkWidget *box;
    appWidgets *w = (appWidgets*) data;

    w->window = gtk_application_window_new (w->app);
    gtk_window_set_application (GTK_WINDOW (w->window), GTK_APPLICATION (w->app));
    box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
    gtk_container_add (GTK_CONTAINER (w->window), box);
    w->da = gtk_drawing_area_new();
    gtk_widget_set_size_request (w->da, 400, 400);
    gtk_box_pack_start (GTK_BOX (box), w->da, TRUE, TRUE, 0);
    g_signal_connect (w->da, "draw", G_CALLBACK (drawEvent), (gpointer) w);
    w->button = gtk_button_new_with_label ("Next");
    g_signal_connect (G_OBJECT (w->button), "clicked", G_CALLBACK (nextCallback), 
                    (gpointer) w);
    gtk_box_pack_start (GTK_BOX (box), w->button, FALSE, TRUE, 0);
    gtk_widget_show_all (GTK_WIDGET (w->window));
    w->redraw = FALSE;
}

int main (int argc, char *argv[])
{
    gint status;
    appWidgets *w = g_malloc (sizeof (appWidgets));

    w->app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
    g_signal_connect (w->app, "activate", G_CALLBACK (activate), (gpointer) w);
    status = g_application_run (G_APPLICATION (w->app), argc, argv);

    g_object_unref (w->app);
    g_free (w);
    w = NULL;
    return status;
}

像往常一样构建程序:

gcc example.c -o example `pkg-config --cflags --libs gtk+-3.0`

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-23
    • 2014-04-21
    • 1970-01-01
    • 1970-01-01
    • 2012-01-07
    • 1970-01-01
    • 1970-01-01
    • 2019-06-15
    相关资源
    最近更新 更多