0

我正在将一些代码从 Java 移植到 Scala,并且在尝试“橡皮筋”时遇到了绘制伪影的问题 - 即绘制一个随鼠标指针移动的矩形。

这在 Java2D 中相对简单,但在 Scala/JavaFX 中运行时遇到了问题。

我在 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 似乎等同于 Graphics2D.setXORMode() 并且它几乎可以工作,但它:

  • 在填充矩形时,有时会留下矩形所在位置的微弱痕迹。
  • 除非线宽是偶数整数,否则在抚摸矩形时会生成不会取消绘制的灰线。
  • 在用偶数的线宽抚摸矩形时,有时会留下矩形所在位置的微弱痕迹。
  • 不能与父组件提供的背景正确异或。

最后一项不是我所期望的,但我想我理解它在做什么(将 Canvas 中未定义的背景视为黑色,因此它在绘制时异或为白色,在未绘制时为黑色,即使它看起来是绿色的从...开始。)

这是一个显示问题的测试用例:

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)
          }
        }
      }
    }
  }
}

此屏幕截图显示了反复移动鼠标后的问题(这是抚摸和 2 像素线宽):

截屏

任何帮助将不胜感激。

4

1 回答 1

1

您可以使用 JavaFX 功能而不是自己移动矩形。你可以使用矩形的setTranstalteX()andsetTranslateY()方法。请参阅Ensemble Sample-->Graphics-->Transforms-->Translate中的 Oracle 示例。这里还有 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); }

}
于 2014-04-05T07:36:01.930 回答