Scala + scalafx でダブルクリック,トリプルクリックを検知する方法


演習中に「ダブルクリックとシングルクリックを区別する方法がわからない」という質問があったので作ったサンプルコードです.

ダブルクリックやトリプルクリックは複数のクリックの組み合わせで構成されているので,最初のクリックをシングルクリックと判定してしまうとダブルクリック操作が必ずシングルクリックの動作を誘発しておかしなことになります.

この問題に対応するには,最初のクリックのときにちょっと待って,後続のクリックがないことを確認する必要があります.要するに短時間だけイベント処理が眠ってくれればいいのですが,アプリケーション全体が眠ってしまうと,後続のクリックを受け取ることができなくなるのでもとの黙阿弥です.そこで,まずイベント処理を独立したスレッドとして実行します.

package wakita.lx14
import scala.compat.Platform
import scalafx.Includes._
import scalafx.application.JFXApp
import scalafx.application.JFXApp.PrimaryStage
import scalafx.scene.Scene
import scalafx.scene.input.{MouseEvent}
import scalafx.scene.layout.{Pane}
object Clicks extends JFXApp {
val canvas = new Pane { }
val DOUBLE_CLICK_WAIT_MS = 300; // milliseconds
var clickedAt = Long.MinValue
canvas.onMousePressed = { (ev: MouseEvent) =>
clickedAt = Platform.currentTime
new Thread {
override def run {
val clicked = clickedAt
Thread.sleep(DOUBLE_CLICK_WAIT_MS)
if (clicked >= clickedAt) println(f"#Clicks = ${ev.clickCount}")
else println(f"Click(${ev.clickCount}) is ignored")
}
}.start
}
stage = new PrimaryStage {
title = "Click Test"
scene = new Scene(600, 400) {
root = canvas
}
}
}

view raw
clicks.scala
hosted with ❤ by GitHub

面倒くさそうな気もしましたが,やってみたら簡単でした.

Scala + scalafx でダブルクリック,トリプルクリックを検知する方法」への1件のフィードバック

  1. FacebookでN村くんから指摘を受けたんですが,DOUBLE_CLICK_WAIT_MS を 300 より大きくするとバグが生じます.たとえば,この値を 2000 に設定すると(つまり,二つのクリックの間隔が2秒以内ならばダブルクリックとして扱う),すごくトロいダブルクリックが実現できそうなのですが,実際には最初のクリックは無視され,二番目のクリックはシングルクリックとして扱われます.

    この原因を理解するには ScalaFX の元となっている JavaFX の仕組みを理解しなくてはいけません.JavaFX がクリックの間に 300ms 以上の間隔を検知すると自動的に clickCount を 0 に初期化するのです.いつか 0 にならないと困りますからね.

    ということで,注意してお使い下さい.

コメントは受け付けていません。