You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 20:13:08