I'm porting some code from Java to Scala and having problems with drawing artefacts when attempting "rubber banding" - i.e. drawing a rectangle that moves with the mouse pointer.
This was relatively simple to do in Java2D, but I'm having problems making it work in Scala/JavaFX.
I'm using Scala 2.10.2, JavaFX 2.2.0-b21 and , Java 1.7.0_06 Java HotSpot(TM) 64-Bit Server VM on OS/X 10.8.4.
graphicsContext2D.globalBlendMode = BlendMode.DIFFERENCE seems equivalent to Graphics2D.setXORMode() and it almost works, but it:
- sometimes leaves faint traces of where the rectangle has been when filling a rectangle.
- produces grey lines that don't undraw when stroking a rectangle unless the line width is an even integer.
- sometimes leaves faint traces of where the rectangle has been when stroking a rectangle with a line width that is an even integer.
- doesn't XOR properly with the background provided by the parent component.
The last item isn't what I expected, but I think I understand what it is doing (treating the undefined background in the Canvas as black, so that it XORs to white on draw, and black on undraw, even though it looked green to start with.)
This is a test case that shows the problem:
import scalafx.application.JFXApp
import scalafx.scene.Scene
import scalafx.scene.paint.Color
import scalafx.Includes._
import scalafx.scene.canvas.{GraphicsContext, Canvas}
import scalafx.scene.layout.Pane
import scalafx.scene.input._
import scalafx.geometry.Rectangle2D
import scalafx.scene.transform.Affine
import scalafx.scene.effect.BlendMode
object Dragger {
var startX: Double = 0.0
var startY: Double = 0.0
var oldRectangle: Rectangle2D = null
def mouseReleased(event: MouseEvent) {
}
def mousePressed(event: MouseEvent) {
startX = event.x
startY = event.y
}
def mouseDragged(g2: GraphicsContext, event: MouseEvent) {
if (oldRectangle != null)
drawRectangle(g2, oldRectangle)
val x0 = math.min(startX, event.x)
val y0 = math.min(startY, event.y)
val newRectangle = new Rectangle2D(x0, y0, math.abs(event.x - startX), math.abs(event.y - startY))
drawRectangle(g2, newRectangle)
oldRectangle = newRectangle
}
def drawRectangle(g2: GraphicsContext, r: Rectangle2D) {
//g2.strokeRect(r.minX, r.minY, r.width, r.height) // <--- stroke instead of fill for grey lines that don't undraw
g2.fillRect(r.minX, r.minY, r.width, r.height)
}
}
object Test extends JFXApp
{
println("javafx.runtime.version: " + System.getProperties.get("javafx.runtime.version"))
println("java.runtime.version: " + System.getProperties.get("java.runtime.version"))
stage = new JFXApp.PrimaryStage {
title = "Hello Stage"
width = 600
height = 472
scene = new Scene {
fill = Color.LIGHTGREEN
root = new Pane {
content = new Canvas(600, 450) {
graphicsContext2D.setStroke(Color.BLUE)
graphicsContext2D.setFill(Color.BLUE)
graphicsContext2D.fillRect(4, 4, 592, 442)
graphicsContext2D.setTransform(new Affine)
graphicsContext2D.globalBlendMode = BlendMode.DIFFERENCE
graphicsContext2D.setStroke(Color.WHITE)
graphicsContext2D.setFill(Color.WHITE)
graphicsContext2D.setLineWidth(1) // <--- increase line width to 2 to fix stroked line undrawing
onMouseDragged = (event: MouseEvent) => {
Dragger.mouseDragged(graphicsContext2D, event)
}
onDragDetected = (event: MouseEvent) => {
//Drag complete
}
onMousePressed = (event: MouseEvent) => {
Dragger.mousePressed(event)
}
onMouseReleased = (event: MouseEvent) => {
Dragger.mouseReleased(event)
}
}
}
}
}
}
This screenshot shows the problem (this is with stroking and a 2 pixel line width) after moving the mouse around repeatedly:
Any help would be greatly appreciated.