简体   繁体   English

如何使用BlendMode.Difference解决ScalaFX / JavaFX中的绘制XOR伪影问题?

[英]How do I solve drawing XOR artefact problems in ScalaFX/JavaFX with BlendMode.Difference?

I'm porting some code from Java to Scala and having problems with drawing artefacts when attempting "rubber banding" - ie drawing a rectangle that moves with the mouse pointer. 我正在将一些代码从Java移植到Scala,并在尝试“橡皮筋”时遇到绘制人工制品的问题-即绘制随鼠标指针移动的矩形。

This was relatively simple to do in Java2D, but I'm having problems making it work in Scala/JavaFX. 在Java2D中这样做相对简单,但是在使它在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. 我正在OS / X 10.8.4上使用Scala 2.10.2,JavaFX 2.2.0-b21和Java 1.7.0_06 Java HotSpot(TM)64位服务器VM。

graphicsContext2D.globalBlendMode = BlendMode.DIFFERENCE seems equivalent to Graphics2D.setXORMode() and it almost works, but it: graphicsContext2D.globalBlendMode = BlendMode.DIFFERENCE似乎与Graphics2D.setXORMode()等效,并且几乎可以使用,但它:

  • 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: 此屏幕快照显示了反复移动鼠标后的问题(这是笔划和2像素的线宽):

屏幕截图

Any help would be greatly appreciated. 任何帮助将不胜感激。

You can use the JavaFX capabilities instead of doing the rectangle move your self. 您可以使用JavaFX功能,而不是通过矩形移动自己。 you can use the setTranstalteX() and setTranslateY() method of the rectangle. 您可以使用矩形的setTranstalteX()setTranslateY()方法。 see Oracle example in the Ensemble Sample-->Graphics-->Transforms-->Translate. 请参阅Ensemble Sample- > Graphics-> Transforms-> Translate中的Oracle示例。 Here also the code from The Ensemble: 这里还有The Ensemble的代码:

public class TranslateSample extends Application {

private void init(Stage primaryStage) {
    Group root = new Group();
    primaryStage.setResizable(false);
    primaryStage.setScene(new Scene(root, 230,220));


    //create 2 rectangles with different color
    Rectangle rect1 = new Rectangle(90, 90, Color.web("#ed4b00", 0.75));
    Rectangle rect2 = new Rectangle(90, 90, Color.web("#ed4b00", 0.5));

    //translate second one
    rect2.setTranslateX(140);

    // rectangle with adjustable translate
    Rectangle rect3 = new Rectangle(40, 130, 60, 60);
    rect3.setFill(Color.DODGERBLUE);
    rect3.setTranslateX(20);
    rect3.setTranslateY(10);

    //show the rectangles
    root.getChildren().addAll(rect2, rect1, rect3);

    //create arrow
    Polygon polygon = createArrow();
    polygon.setLayoutX(110);
    polygon.setLayoutY(30);
    polygon.setRotate(90);

    root.getChildren().addAll(polygon);
}

public static Polygon createArrow() {
    Polygon polygon = new Polygon(new double[]{
        7.5, 0,
        15, 15,
        10, 15,
        10, 30,
        5, 30,
        5, 15,
        0, 15
    });

    polygon.setFill(Color.web("#ff0900"));

    return polygon;

}

public double getSampleWidth() { return 230; }

public double getSampleHeight() { return 220; }

@Override public void start(Stage primaryStage) throws Exception {
    init(primaryStage);
    primaryStage.show();
}
public static void main(String[] args) { launch(args); }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM