Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make ScalaFX scene draggable

Tags:

scalafx

I am actually working on an ScalaFX application without window decorations. What I want to do is making it draggable, so that a user can move it anyhow.

I managed moving the stage by simply writing the coordinates of the dragging mouse into the stage X/Y coordinates. However, that resulted in a laggy and flickering window.

How can dragging a stage be implemented smoothly in ScalaFX?

like image 340
smoes Avatar asked Feb 27 '26 11:02

smoes


1 Answers

Here's an example that works well for me. It's adapted from one example in the book "JavaFX 8 Introduction by Example". How does it compare to your attempt?

import scalafx.Includes._
import scalafx.application.JFXApp
import scalafx.application.JFXApp.PrimaryStage
import scalafx.geometry.Point2D
import scalafx.scene.Scene
import scalafx.scene.input.MouseEvent
import scalafx.scene.paint.Color
import scalafx.stage.{WindowEvent, StageStyle}

object DraggableApp extends JFXApp {

  private var anchorPt: Point2D = null
  private var previousLocation: Point2D = null

  stage = new PrimaryStage {
    initStyle(StageStyle.TRANSPARENT)
    scene = new Scene {
      fill = Color.rgb(0, 0, 0, 1.0)
    }
  }

  // Initialize stage to be movable via mouse
  initMovablePlayer()

  /**
   * Initialize the stage to allow the mouse cursor to move the application
   * using dragging.
   */
  private def initMovablePlayer(): Unit = {
    val scene = stage.getScene

    scene.onMousePressed = (event: MouseEvent) => anchorPt = new Point2D(event.screenX, event.screenY)

    scene.onMouseDragged = (event: MouseEvent) =>
      if (anchorPt != null && previousLocation != null) {
        stage.x = previousLocation.x + event.screenX - anchorPt.x
        stage.y = previousLocation.y + event.screenY - anchorPt.y
      }

    scene.onMouseReleased = (event: MouseEvent) => previousLocation = new Point2D(stage.getX, stage.getY)

    stage.onShown = (event: WindowEvent) => previousLocation = new Point2D(stage.getX, stage.getY)
  }
}

Edit: About you question on stage resizing, I tried the following variant, which resizes the stage when right-clicking and dragging; I don't see any flickering (on OS X).

import javafx.scene.{input => jfxsi}
// (...)

object DraggableApp extends JFXApp {

  private var previousHeight = 0.0
  private var previousWidth = 0.0
  // (...)

  private def initMovablePlayer(): Unit = {
    val scene = stage.getScene

    scene.onMousePressed = (event: MouseEvent) => anchorPt = new Point2D(event.screenX, event.screenY)

    scene.onMouseDragged = (event: MouseEvent) =>
      if (anchorPt != null && previousLocation != null) {
        if (event.getButton == jfxsi.MouseButton.PRIMARY) {
          stage.x = previousLocation.x + event.screenX - anchorPt.x
          stage.y = previousLocation.y + event.screenY - anchorPt.y
        } else if (event.getButton == jfxsi.MouseButton.SECONDARY) {
          stage.width = previousWidth + event.screenX - anchorPt.x
          stage.height = previousHeight + event.screenY - anchorPt.y
        }
      }

    scene.onMouseReleased = (_: MouseEvent) => reset()

    stage.onShown = (_: WindowEvent) => reset()

    def reset (): Unit = {
      previousLocation = new Point2D(stage.getX, stage.getY)
      previousHeight = stage.getHeight
      previousWidth = stage.getWidth
    }
  }
}
like image 72
Cyäegha Avatar answered Mar 02 '26 15:03

Cyäegha



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!