如何使鼠标事件处理更容易?

有时候我必须实现像自定义拖放这样的功能 . 代码可能如下所示:

bool mouse_down = false;
Vec2 mouse_pos;
void on_mouse_down() {
  mouse_down = true;
  mouse_pos = cursor_pos();
}
void on_mouse_move() {
  if(mouse_down) {
    Vec2f c = cursor_pos();
    Vec2f d = c - mouse_pos;
    // dragging. make objects tracing the cursor.
    // ...
  }
}
void on_mouse_up() {
  mouse_down = false;
  // dropped
  // ...
}

我知道这很好用,但我不喜欢冗余变量和分离程序这样的事情 . 在IP(命令式编程)中,它可能是不可避免的;我的问题是,在FP(函数式编程)中有没有更好的方法来处理这种事情?无论编程语言是什么,Lisp,Scheme,F#,Ruby等,还是在IP中做到这一点的更好的方法,任何想法和建议都表示赞赏?

回答(1)

2 years ago

由于没有人尝试过一天的答案,我会试一试 . 我理解您正在讨论的问题,但答案可能取决于操作系统,语言及其运行时库 .

一般的想法是,当鼠标出现故障时,会产生异步计算 . 这个事件计算"blocks",并在获取它们自己的循环中处理它们,做你需要做的事情;当鼠标按钮向上时它存在 . 虽然这看起来像是一个命令式线程,但实际上,当计算得到"blocked"时,它只是控制它从哪里开始(主要的GUI线程调用鼠标按下事件,大概) . 以这种方式,状态被封装到看起来像词法局部计算范围的内容中 . 这种魔法必须由语言的运行时来处理,所以这就是我们可以用语言和操作系统无关的方式得到答案 .

至于这种实现的一个例子,检查this answerarticle by Tomas Petricek,两者都讨论你的问题,但是在Windows,.NET和F#的狭窄设置中 . 有一本同一个Perticek的书,Real World Functional Programming: With Examples in F# and C#,令人惊讶的是,在C#中表达了相同的想法,通常不被认为是一种功能语言 . 第十六章,如果我的记忆能为我服务,那就是你的 .

至于在IP / OO语言程序中封装状态,您可以在mouse_down处理程序中创建类的实例 . 该实例将向运行时注册以接收其他鼠标和UI事件,处理它们,完成所有工作,并在需要时(鼠标上升或窗口系统取消捕获模式),取消注册并销毁自身 . 不像函数式语言那样优雅,但在一般的UI类中保持可变状态仍然要好得多 .