如何通过GtkEventControllerScroll(滚动事件)在Cairo画布上移动图形?
问题修复:通过GtkEventControllerScroll水平移动GtkDrawingArea中的圆形
你的代码存在几个关键问题,导致滚动无法正确移动圆形,以下是问题分析和修复方案:
代码中的错误点
- 回调参数类型错误:
_scroll_controller_scroll函数的最后一个参数gpointer *widget多了一个星号,应该是gpointer widget,类型不匹配会导致传递的控件指针失效。 - 滚动值处理错误:GtkEventControllerScroll的
x参数是滚动增量,不是绝对位置,直接赋值给pos会导致圆形跳变,应该累加增量来更新位置。 - 控制器标志冲突:创建滚动控制器时同时使用
GTK_EVENT_CONTROLLER_SCROLL_HORIZONTAL和GTK_EVENT_CONTROLLER_SCROLL_BOTH_AXES,这两个标志互斥,只需保留GTK_EVENT_CONTROLLER_SCROLL_HORIZONTAL即可。 - 打印格式错误:
g_print中用%d打印gdouble类型的x和y,会输出错误数值,应改为%lf。 - 回调缺少返回值:事件回调函数需要返回
gboolean类型值,需添加return TRUE;表示事件已被处理。
修复后的完整代码
#include <gtk/gtk.h> int pos = 10; static void draw_function (GtkDrawingArea *darea, cairo_t *cr, int width, int height, gpointer user_data) { cairo_set_source_rgb(cr, 0, 0, 0); cairo_paint (cr); cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); cairo_set_line_width (cr, 1.5); // 限制pos范围,避免圆形移出窗口 pos = pos < 4 ? 4 : (pos > width - 4 ? width - 4 : pos); cairo_arc (cr, pos, 10, 4, 0.0, 2 * G_PI); cairo_stroke (cr); } static gboolean _scroll_controller_scroll (GtkEventControllerScroll *scroll, gdouble x, gdouble y, gpointer widget) { g_print("%lf %lf\n", x, y); // 累加水平滚动增量 pos += (int)x; gtk_widget_queue_draw ((GtkWidget *)widget); // 返回TRUE表示事件已处理 return TRUE; } static void activate (GtkApplication* app, gpointer user_data) { GtkWidget *window = gtk_application_window_new (app); gtk_window_set_title (GTK_WINDOW (window), "Color"); gtk_window_set_default_size (GTK_WINDOW (window), 300, 200); GtkWidget *dr = gtk_drawing_area_new (); gtk_window_set_child ((GtkWindow *)window, dr); gtk_drawing_area_set_content_width (GTK_DRAWING_AREA (dr), 300); gtk_drawing_area_set_content_height (GTK_DRAWING_AREA (dr), 200); gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (dr), draw_function, NULL, NULL); // 只使用水平滚动标志 GtkEventController *controller = gtk_event_controller_scroll_new (GTK_EVENT_CONTROLLER_SCROLL_HORIZONTAL); gtk_widget_add_controller (dr, GTK_EVENT_CONTROLLER (controller)); // 移除不必要的传播阶段设置,默认即可 g_signal_connect (controller, "scroll", G_CALLBACK (_scroll_controller_scroll), dr); gtk_window_present (GTK_WINDOW (window)); } int main (int argc, char **argv) { GtkApplication *app; int status; app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE); g_signal_connect (app, "activate", G_CALLBACK (activate), NULL); status = g_application_run (G_APPLICATION (app), argc, argv); g_object_unref (app); return status; }
额外优化
修复后的代码添加了pos的范围限制,确保圆形不会完全移出窗口边界(限制在4到窗口宽度-4之间,对应圆形半径4)。
内容的提问来源于stack exchange,提问作者dibyendu
相关产品推荐
相关产品推荐

