按下按钮后如何在 Cairo gtk3.0 中正确绘制一条线
how to correctly draw a line in Cairo gtk3.0 after pressing a button
我正在关注 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) 用于重绘。我注意到的唯一问题是,当我单击按钮时,它不会立即绘制,但我必须隐藏 window 或拉伸 window 才能显示出来。我想我需要添加某种 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);
}
您已经为(大概)绘图区域编写了绘图处理程序,但将其连接到按钮的单击信号。这两个具有完全不同的函数签名,因此段错误不足为奇。
不要直接在按钮的单击处理程序上绘制,而是更改某些应用程序状态(如 gboolean should_draw_line
)并使用 gtk_widget_queue_draw ()
将绘图区域标记为需要重绘。然后在绘图区的绘图处理程序中根据应用程序状态决定绘制什么(如should_draw_line
)。
查看您链接到的示例后,它似乎几乎完全按照我的建议进行...
行
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开发的新手。
我正在关注 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) 用于重绘。我注意到的唯一问题是,当我单击按钮时,它不会立即绘制,但我必须隐藏 window 或拉伸 window 才能显示出来。我想我需要添加某种 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);
}
您已经为(大概)绘图区域编写了绘图处理程序,但将其连接到按钮的单击信号。这两个具有完全不同的函数签名,因此段错误不足为奇。
不要直接在按钮的单击处理程序上绘制,而是更改某些应用程序状态(如 gboolean should_draw_line
)并使用 gtk_widget_queue_draw ()
将绘图区域标记为需要重绘。然后在绘图区的绘图处理程序中根据应用程序状态决定绘制什么(如should_draw_line
)。
查看您链接到的示例后,它似乎几乎完全按照我的建议进行...
行
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开发的新手。