【问题标题】:how to correctly draw a line in Cairo gtk3.0 after pressing a button按下按钮后如何在Cairo gtk3.0中正确画线
【发布时间】:2016-05-04 22:19:33
【问题描述】:

我正在关注 zetecode (http://zetcode.com/gfx/cairo/basicdrawing/) 并尝试构建我的第一个在按下按钮后绘制一条线的示例,但它失败了,我就是不知道为什么。单击按钮时出现segmentation fault 错误。

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

static void do_drawing(cairo_t *);

static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr, 
    gpointer user_data)
{
    do_drawing(cr);
    return FALSE;
}


static void do_drawing(cairo_t *cr)
{
    cairo_set_source_rgb(cr,0,0,0);
    cairo_set_line_width(cr,0.5);

    cairo_move_to(cr,400,400);
    cairo_line_to(cr,400,200);

    cairo_stroke(cr);


}


int main(int argc, char *argv[])
{
    GtkWidget *window;
    GtkWidget *darea;

    gtk_init(&argc, &argv);

    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_default_size(GTK_WINDOW(window), 800, 480);
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);

    darea = gtk_drawing_area_new();
    GtkWidget *btn_draw = gtk_button_new_with_label("Draw a line");


    GtkWidget *mainwindow = gtk_grid_new();
        gtk_grid_set_row_spacing (GTK_GRID (mainwindow), 16);
        gtk_grid_set_column_spacing (GTK_GRID (mainwindow), 16);
    gtk_grid_set_row_homogeneous(GTK_GRID(mainwindow), TRUE);
    gtk_grid_set_column_homogeneous(GTK_GRID(mainwindow), TRUE);

    gtk_widget_set_margin_left(mainwindow,20);
    gtk_widget_set_margin_right(mainwindow,20);
    gtk_widget_set_margin_top(mainwindow,20);
    gtk_widget_set_margin_bottom(mainwindow,20);

    gtk_grid_attach(GTK_GRID(mainwindow),btn_draw,0,0,1,1);  
    gtk_grid_attach(GTK_GRID(mainwindow),darea,1,0,5,1);  

    gtk_container_add(GTK_CONTAINER(window),mainwindow);

    g_signal_connect(G_OBJECT(btn_draw),"clicked",G_CALLBACK(on_draw_event),NULL);

    gtk_widget_show_all(window);

        gtk_main ();

        return(0);

}

这就是它的样子:

PS:

我听从@jku 的建议,使用 gboolean draw_a_line 记录按钮状态,并使用 gtk_widget_queue_draw(widget) 进行重绘。我注意到的唯一问题是,当我单击按钮时,它不会立即绘制,但我必须隐藏窗口或拉伸窗口才能显示出来。我想我需要添加某种 automatic_update() 函数,但我是 GUI 设计的新手,所以有人可以告诉我如何在单击按钮后立即显示该行吗?

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

static void do_drawing(cairo_t *);
GtkWidget *window;
GtkWidget *darea;
gboolean draw_a_line = false;

static gboolean on_draw_event(GtkWidget *widget, GdkEventExpose *event, 
    gpointer user_data)
{
    cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(GTK_WIDGET(widget)));
    do_drawing(cr);

    return FALSE;
}


static void do_drawing(cairo_t *cr)
{
    cairo_set_source_rgb(cr,0,0,0);
    cairo_set_line_width(cr,0.5);
    if (draw_a_line){
        cairo_move_to(cr,400,400);
        cairo_line_to(cr,400,200);
        cairo_stroke(cr);
    }

}


static void on_clicked(GtkWidget *widget, gpointer data)
{
    draw_a_line = true;
    gtk_widget_queue_draw(widget);

}

int main(int argc, char *argv[])
{


    gtk_init(&argc, &argv);

    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_default_size(GTK_WINDOW(window), 800, 480);
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);

    darea = gtk_drawing_area_new();
    GtkWidget *btn_draw = gtk_button_new_with_label("Draw a line");


    GtkWidget *mainwindow = gtk_grid_new();
        gtk_grid_set_row_spacing (GTK_GRID (mainwindow), 16);
        gtk_grid_set_column_spacing (GTK_GRID (mainwindow), 16);
    gtk_grid_set_row_homogeneous(GTK_GRID(mainwindow), TRUE);
    gtk_grid_set_column_homogeneous(GTK_GRID(mainwindow), TRUE);

    gtk_widget_set_margin_left(mainwindow,20);
    gtk_widget_set_margin_right(mainwindow,20);
    gtk_widget_set_margin_top(mainwindow,20);
    gtk_widget_set_margin_bottom(mainwindow,20);

    gtk_grid_attach(GTK_GRID(mainwindow),btn_draw,0,0,1,1);  
    gtk_grid_attach(GTK_GRID(mainwindow),darea,1,0,5,1);  

    gtk_container_add(GTK_CONTAINER(window),mainwindow);


    g_signal_connect(G_OBJECT(darea), "draw", G_CALLBACK(on_draw_event), NULL); 
    g_signal_connect(G_OBJECT(btn_draw),"clicked",G_CALLBACK(on_clicked),darea);

    gtk_widget_show_all(window);

        gtk_main ();

        return(0);

}

【问题讨论】:

  • on_draw_event() 应该有一个 cairo_t 传递给它,但你没有在任何地方传递一个。
  • 谢谢!就是那个问题。 @oldtechaa

标签: gtk gtk3 cairo


【解决方案1】:

您已经为(大概)绘图区域编写了一个绘图处理程序,但将它连接到按钮的 clicked 信号。这两个具有完全不同的函数签名,因此段错误不足为奇。

不要直接在按钮的单击处理程序上绘制,而是更改某些应用程序状态(如gboolean should_draw_line)并使用gtk_widget_queue_draw () 将绘图区域标记为需要重绘。然后在绘图区的draw handler中根据应用状态决定绘制什么(比如should_draw_line)。

在查看了您链接到的示例之后,它似乎几乎完全按照我的建议做......

【讨论】:

  • 谢谢先生!!这真的很有帮助,在我按照你的建议更改了我的代码之后,它仍然有一个问题。我编辑了我的帖子,你能看一下吗?再次感谢你
  • 看起来几乎正确,但您在错误的小部件(按钮)上调用 gtk_widget_queue_draw()。您应该在绘图区域调用它,因为这需要重绘。
  • 完美,正是我需要的。
【解决方案2】:

线

gtk_widget_queue_draw(widget);

应该是

gtk_widget_queue_draw((GtkWidget*)data);

在按下按钮时重绘。

第一个参数'GtkWidget *widget'是'button'(它是自动传递的),第二个参数是'darea'小部件。发生的事情是,按下时按钮被重绘:D

'on_clicked' 函数代码:

static void on_clicked(GtkWidget *widget, gpointer data)
{
    draw_a_line = TRUE;
    gtk_widget_queue_draw((GtkWidget*)data);
}

顺便说一句,感谢您发布此消息。我从你的代码中学会了在 GTK 中画线。我也是 GUI 开发的新手。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-08-28
    • 1970-01-01
    • 2016-12-05
    • 2020-03-06
    • 2020-11-13
    • 2021-11-25
    • 1970-01-01
    相关资源
    最近更新 更多