3

在 JavaFX 2.2 中绘制清晰、不透明的细线的最佳方法是什么?

文档说,其中一个strokeWidth0.0d是一条细线,但它根本不可见。值> 0.0d and <1.0d显示的线条非常好,但也没有表现出不透明的行为。当一条线切割另一条线时,相交点比线的其余部分轻(我希望这种行为来自具有一定透明度的线)。最后,1.0d绘制一条宽度为几个像素的白线。

这是我的测试代码:

LineBuilder.create().startX(i*gridSize).startY(0).endX(i*gridSize).endY(height).smooth(false).stroke(Color.WHITE).strokeWidth(0.5d).fill(Color.WHITE).build();           
4

1 回答 1

3

您可以使用Region子类,例如Parent的Pane ,并将snapToPixel设置为 true。

此外,请参阅坐标系上的节点文档。

在设备像素级别,整数坐标映射到角落和像素之间的裂缝和像素的中心出现在整数像素位置之间的中点。因为所有坐标值都是用浮点数指定的,所以坐标可以精确地指向这些角(当浮点值具有精确的整数值时)或像素上的任何位置。例如,坐标 (0.5, 0.5) 将指向舞台左上角像素的中心。类似地,尺寸为 10 x 10 的 (0, 0) 矩形将从舞台左上角像素的左上角跨越到第 10 条扫描线上第 10 个像素的右下角。该矩形内最后一个像素的像素中心将位于坐标 (9.5, 9.5) 处。

另请参阅形状文档:

大多数节点往往只对其应用整数转换,并且通常它们也使用整数坐标定义。对于这种常见情况,具有直线边缘的形状填充往往很清晰,因为它们与落在整数设备坐标上的像素之间的裂缝对齐,因此往往会自然地覆盖整个像素。另一方面,对这些相同的形状进行描边通常会导致轮廓模糊,因为默认描边属性指定默认描边宽度为 1.0 坐标,该坐标通常恰好映射到 1 个设备像素,并且描边应该跨越形状的边界, 落在边界两侧的一半。由于许多常见形状的边框往往直接落在整数坐标上,并且这些整数坐标通常精确映射到整数设备位置,因此边框往往会导致形状边框两侧的像素行和列的覆盖率为 50%而不是 100% 覆盖其中之一。因此,填充通常可能是清脆的,但笔画通常是模糊的。

避免这些模糊轮廓的两种常见解决方案是使用完全覆盖更多像素的更宽笔划 - 如果没有有效的缩放变换,通常 2.0 的笔划宽度将实现这一点 - 或者指定 StrokeType.INSIDE 或 StrokeType.OUTSIDE 笔划样式 - 这会将默认的单个单位笔划偏向于形状边框内部或外部的完整像素行或列之一。

因此,如果您将节点留在不 snapToPixel 的组或区域中,您可以按照 Shape 文档中的上述说明进行操作。

这是一些示例代码:

import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.scene.shape.LineBuilder;
import javafx.scene.shape.StrokeType;
import javafx.scene.text.Text;
import javafx.stage.Stage;

/** http://stackoverflow.com/questions/11886230/how-to-draw-a-crisp-opaque-hairline-in-javafx-2-2 */
public class LineWidths extends Application {
  public static void main(String[] args) { launch(args); }

  @Override public void start(Stage stage) {
    Line fuzzyline = LineBuilder.create()
        .startX(5).startY(50)
        .endX(90).endY(50)
        .stroke(Color.BLACK).strokeWidth(1)
      .build();
    Line hairline = LineBuilder.create()
        .startX(4.5).startY(99.5)
        .endX(89.5).endY(99.5)
        .stroke(Color.BLACK).strokeWidth(1)
      .build();
    Line fatline = LineBuilder.create()
        .startX(5).startY(150)
        .endX(90).endY(150)
        .stroke(Color.BLACK).strokeWidth(1).strokeType(StrokeType.OUTSIDE)
      .build();
    Pane snappedPane = new Pane();
    Line insideline = LineBuilder.create()
        .startX(5).startY(25)
        .endX(90).endY(25)
        .stroke(Color.BLACK).strokeWidth(1)
      .build();
    snappedPane.setSnapToPixel(true);
    snappedPane.getChildren().add(insideline);
    snappedPane.setPrefSize(100, 50);
    snappedPane.relocate(-0.5, 174.5);

    stage.setScene(
      new Scene(
        new Group(
          fuzzyline, hairline, fatline, snappedPane,
          new Text(10, 40, "fuzzyline"),  
          new Text(10, 90, "hairline"),  
          new Text(10, 140, "fatline"),  
          new Text(10, 190, "snappedPane")
        ), 100, 250
      )
    );
    stage.show();
  }
}

线型样本

于 2012-08-09T16:24:01.887 回答