如何在JavaFX中创建大小可调的不同颜色线段的十字?

1u4esq0p  于 2023-01-07  发布在  Java
关注(0)|答案(4)|浏览(141)

我需要做一个十字架与两个不同颜色的部分一样,在下面的图片。

片段可以改变大小,这是一个通过绑定或其他方式考虑的元素。
如何在JavaFX中创建这个图形元素?
我用虚线看,但我不想在每一段之间的空间,但不同的颜色。我必须把两个假想的线?
我用的是JavaFX 17。
谢谢你的帮忙
编辑01/04:
我已经做了一些测试,但破折号不适合正确。
我想把每一笔画在垂直线上间隔50px,在水平线上间隔9.7px,但是当我正确地填充表格时,它们没有给我正确的尺寸。
我是否输入了错误的数据?
代码:

public void initialize(URL url, ResourceBundle resourceBundle)
    {
        var line = new Line(200, 200, 200, 600);
        line.setStroke(Paint.valueOf("#FF0000"));
        line.setStrokeWidth(10.0);

        var line2 = new Line(200,200,200,600);
        line2.setStroke(Paint.valueOf("#00FF13"));
        line2.setStrokeWidth(10.0);
        line2.getStrokeDashArray().addAll(50.0d, 50.0d);

        var line3 = new Line(250, 650, 650, 650);
        line3.setStroke(Paint.valueOf("#FF0000"));
        line3.setStrokeWidth(10.0);

        var line4 = new Line(250, 650, 650, 650);
        line4.setStroke(Paint.valueOf("#00FF13"));
        line4.setStrokeWidth(10.0);
        line4.getStrokeDashArray().addAll(9.7d, 9.7d);

        var root = new Group(line, line2, line3, line4);

        anchorPane.getChildren().add(root);
    }

代码结果:

yc0p9oo0

yc0p9oo01#

你可以画两条互相重叠的虚线,一条是红色的,另一条是绿色的。为了用第二条来填充空白,你只需要设置合适的虚线偏移量。

v6ylcynt

v6ylcynt2#

使用单独线条的解决方案(每种颜色的虚线不叠加)

  • 请注意,我已经将您的颜色替换为对色盲或色弱患者友好的颜色。*

您可以使用描边的线性渐变对单个线条执行此操作。
例如,若要创建使用50px垂直虚线重复两种颜色的线性渐变,请创建从(0,0)到(0,100)的线性渐变,其中第一种颜色为0和50%,第二种颜色为50%和100%:

Paint verticalStroke = new LinearGradient(0,0,0,100, false,
            CycleMethod.REPEAT,
            new Stop(0, color1),
            new Stop(0.5, color1),
            new Stop(0.5, color2),
            new Stop(1, color2)
    );

Paint verticalStroke = LinearGradient.valueOf(
            "linear-gradient(from 0px 0px to 0px 100px, repeat, #FC8D62 0%, #FC8D62 50%, #66C2A5 50%, #66C2A5 100%)"
    );

下面是一个完整的工作示例。自定义窗格将线条布置为十字形,这会对窗格大小的变化做出React。线条的虚线效果与线条大小无关。

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.*;
import javafx.scene.shape.Line;
import javafx.stage.Stage;

import java.io.IOException;

public class HelloApplication extends Application {
    @Override
    public void start(Stage stage) throws IOException {

        final Color color1 = Color.valueOf("#FC8D62");
        final Color color2 = Color.valueOf("#66C2A5");
        
        final double verticalDashSize = 50;
        final double horizontalDashSize = 9.7;

        Line upperVerticalLine = createLine();
        Line lowerVerticalLine = createLine();
        Line leftHorizontalLine = createLine();
        Line rightHorizontalLine = createLine();

        Stop[] stops = new Stop[] {
                new Stop(0, color1),
                new Stop(0.5, color1),
                new Stop(0.5, color2),
                new Stop(1, color2)
        };

        Paint verticalStroke = new LinearGradient(
                0,0,0,2*verticalDashSize, false,
                CycleMethod.REPEAT, stops
        );

        upperVerticalLine.setStroke(verticalStroke);
        lowerVerticalLine.setStroke(verticalStroke);

        Paint horizontalStroke = new LinearGradient(
                0, 0, 2*horizontalDashSize, 0, false,
                CycleMethod.REPEAT, stops
        );

        leftHorizontalLine.setStroke(horizontalStroke);
        rightHorizontalLine.setStroke(horizontalStroke);

        Pane root = new Pane(upperVerticalLine, lowerVerticalLine, leftHorizontalLine, rightHorizontalLine) {
            
            private static final double PAD = 20 ;
            @Override
            protected void layoutChildren() {
                double w = getWidth();
                double h = getHeight();
                upperVerticalLine.setStartX(w/2);
                upperVerticalLine.setEndX(w/2);
                upperVerticalLine.setStartY(PAD);
                upperVerticalLine.setEndY(h/2-PAD);
                lowerVerticalLine.setStartX(w/2);
                lowerVerticalLine.setEndX(w/2);
                lowerVerticalLine.setStartY(h/2+PAD);
                lowerVerticalLine.setEndY(h-PAD);

                leftHorizontalLine.setStartX(PAD);
                leftHorizontalLine.setStartY(h/2);
                leftHorizontalLine.setEndX(w/2-PAD);
                leftHorizontalLine.setEndY(h/2);
                rightHorizontalLine.setStartX(w/2+PAD);
                rightHorizontalLine.setStartY(h/2);
                rightHorizontalLine.setEndX(w-PAD);
                rightHorizontalLine.setEndY(h/2);
            }

        };
        
        Scene scene =new Scene(root, 800, 800);
        stage.setScene(scene);
        stage.show();

    }

    private Line createLine() {
        Line line = new Line();
        line.setStrokeWidth(10);
        return line ;
    }

    public static void main(String[] args) {
        launch();
    }
}

更新以解决备注

请注意,这并不限于水平线或垂直线。只要LinearGradientstartXstartYendXendY参数选择为与线平行,这将起作用。如果线的斜率可能发生变化,stroke将需要相应地更新。以下版本创建了对角线,如果窗口大小被调整,这些对角线将具有任意斜率:

import javafx.application.Application;
import javafx.geometry.Point2D;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.paint.CycleMethod;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.scene.shape.Line;
import javafx.stage.Stage;

import java.io.IOException;
import java.util.List;

public class HelloApplication extends Application {
    @Override
    public void start(Stage stage) throws IOException {

        final Color color1 = Color.valueOf("#FC8D62");
        final Color color2 = Color.valueOf("#66C2A5");

        final double verticalDashSize = 50;
        final double horizontalDashSize = 9.7;

        Line upperVerticalLine = createLine();
        Line lowerVerticalLine = createLine();
        Line leftHorizontalLine = createLine();
        Line rightHorizontalLine = createLine();

        Line upperLeftDiag = createLine();
        Line upperRightDiag = createLine();
        Line lowerLeftDiag = createLine();
        Line lowerRightDiag = createLine();

        Stop[] stops = new Stop[] {
                new Stop(0, color1),
                new Stop(0.5, color1),
                new Stop(0.5, color2),
                new Stop(1, color2)
        };

        Pane root = new Pane(upperVerticalLine, lowerVerticalLine, leftHorizontalLine, rightHorizontalLine,
                upperLeftDiag, upperRightDiag, lowerLeftDiag, lowerRightDiag) {

            private static final double PAD = 20 ;
            @Override
            protected void layoutChildren() {
                double w = getWidth();
                double h = getHeight();
                upperVerticalLine.setStartX(w/2);
                upperVerticalLine.setEndX(w/2);
                upperVerticalLine.setStartY(PAD);
                upperVerticalLine.setEndY(h/2-PAD);

                lowerVerticalLine.setStartX(w/2);
                lowerVerticalLine.setEndX(w/2);
                lowerVerticalLine.setStartY(h/2+PAD);
                lowerVerticalLine.setEndY(h-PAD);

                leftHorizontalLine.setStartX(PAD);
                leftHorizontalLine.setStartY(h/2);
                leftHorizontalLine.setEndX(w/2-PAD);
                leftHorizontalLine.setEndY(h/2);

                rightHorizontalLine.setStartX(w/2+PAD);
                rightHorizontalLine.setStartY(h/2);
                rightHorizontalLine.setEndX(w-PAD);
                rightHorizontalLine.setEndY(h/2);

                upperLeftDiag.setStartX(PAD);
                upperLeftDiag.setStartY(PAD);
                upperLeftDiag.setEndX(w/2-PAD);
                upperLeftDiag.setEndY(h/2-PAD);

                upperRightDiag.setStartX(w-PAD);
                upperRightDiag.setStartY(PAD);
                upperRightDiag.setEndX(w/2+PAD);
                upperRightDiag.setEndY(h/2-PAD);

                lowerLeftDiag.setStartX(PAD);
                lowerLeftDiag.setStartY(h-PAD);
                lowerLeftDiag.setEndX(w/2-PAD);
                lowerLeftDiag.setEndY(h/2+PAD);

                lowerRightDiag.setStartX(w-PAD);
                lowerRightDiag.setStartY(h-PAD);
                lowerRightDiag.setEndX(w/2+PAD);
                lowerRightDiag.setEndY(h/2+PAD);

                List.of(upperVerticalLine, lowerVerticalLine, leftHorizontalLine, rightHorizontalLine,
                                upperLeftDiag, upperRightDiag, lowerLeftDiag, lowerRightDiag)
                        .forEach(
                        line -> createGradientForLine(line, 25, color1, color2)
                );
            }

            private void createGradientForLine(Line line, double segmentLength, Color color1, Color color2) {
                Point2D lineVector = new Point2D(line.getEndX(), line.getEndY()).subtract(line.getStartX(), line.getStartY());
                Point2D normalizedVector = lineVector.normalize().multiply(2*segmentLength);
                Stop[] stops = new Stop[] {
                    new Stop(0, color1),
                    new Stop(0.5, color1),
                    new Stop(0.5, color2),
                    new Stop(1, color2)
                };
                LinearGradient gradient = new LinearGradient(0, 0, normalizedVector.getX(), normalizedVector.getY(), false,
                        CycleMethod.REPEAT, stops);
                line.setStroke(gradient);
            }

        };

        Scene scene =new Scene(root, 800, 800);
        stage.setScene(scene);
        stage.show();

    }

    private Line createLine() {
        Line line = new Line();
        line.setStrokeWidth(10);
        return line ;
    }

    public static void main(String[] args) {
        launch();
    }
}

我不认为这可以用于任意路径,但它将工作的任何直线。

v6ylcynt

v6ylcynt3#

    • 使用Group作为局部坐标创建直线**

该方法基于Mipa's answer
每一对线都是重叠的,但是我们可以用setStrokeDashOffset方法做一个偏移来看到下面的线。每一条线都是Group节点的子节点,它被用作局部坐标系。一旦创建了一个新的cross,我们可以把它放在任何我们想要的地方,而不需要改变任何局部坐标。这是一个单独的javafx类,你可以试试。抱歉硬编码

    • Java应用程序**
public class App extends Application {

    @Override
    public void start(Stage stage) {

        var cross = getCross(400, 20, 5, 30, Color.GREEN, Color.CORAL);
        var cross1 = getCross(100, 10, 3, 10, Color.YELLOW, Color.VIOLET);

        var scene = new Scene(new HBox(cross, cross1), 640, 480);
        stage.setScene(scene);
        stage.setTitle("cross ");
        stage.show();
    }

    public static void main(String[] args) {
        launch();
    }

    private Group getCross(double size, double centerOffset, int strokeWidth, double dashSize, Color color1, Color color2) {

// up lines 
        var line = new Line(0, -centerOffset, 0, -size / 2);
        line.setStroke(color1);
        line.setStrokeWidth(strokeWidth);
        line.getStrokeDashArray().add(dashSize);

        var line1 = new Line(0, -centerOffset, 0, -size / 2);
        line1.setStroke(color2);
        line1.setStrokeWidth(strokeWidth);
        line1.getStrokeDashArray().add(dashSize);
        line1.setStrokeDashOffset(dashSize);

// down lines 
        var line2 = new Line(0, centerOffset, 0, size / 2);
        line2.setStroke(color1);
        line2.setStrokeWidth(strokeWidth);
        line2.getStrokeDashArray().add(dashSize);

        var line3 = new Line(0, centerOffset, 0, size / 2);
        line3.setStroke(color2);
        line3.setStrokeWidth(strokeWidth);
        line3.setStrokeDashOffset(dashSize);
        line3.getStrokeDashArray().add(dashSize);

        // right lines        
        var line4 = new Line(centerOffset, 0, size / 2, 0);
        line4.setStroke(color1);
        line4.setStrokeWidth(strokeWidth);
        line4.getStrokeDashArray().add(dashSize);

        var line5 = new Line(centerOffset, 0, size / 2, 0);
        line5.setStroke(color2);
        line5.setStrokeWidth(strokeWidth);
        line5.setStrokeDashOffset(dashSize);
        line5.getStrokeDashArray().add(dashSize);

        // left lines        
        var line6 = new Line(-centerOffset, 0, -size / 2, 0);
        line6.setStroke(color1);
        line6.setStrokeWidth(strokeWidth);
        line6.getStrokeDashArray().add(dashSize);

        var line7 = new Line(-centerOffset, 0, -size / 2, 0);
        line7.setStroke(color2);
        line7.setStrokeWidth(strokeWidth);
        line7.setStrokeDashOffset(dashSize);
        line7.getStrokeDashArray().add(dashSize);

        return new Group(line, line1, line2, line3, line4, line5, line6, line7);
    }

}
    • 结果**

f2uvfpb9

f2uvfpb94#

正如@James_D所指出的,LinearGradient是正确的选择。下面是我的方法,它使用Rectangle,放入LinearGradient,然后旋转和重新定位Rectangle来做十字线。

class CrossHair : Application() {
   override fun start(primaryStage: Stage?) {
      primaryStage?.run {
         scene = Scene(createContent(), 500.0, 400.0)
         show()
      }
   }

   private fun createContent(): Region {

      return Pane().apply {
         children += rectangle(150.0, 4).apply {
            translateX = 170.0
            translateY = 100.0
            rotate = 90.0
         }
         children += rectangle(150.0, 4).apply {
            translateX = 170.0
            translateY = 290.0
            rotate = 90.0
         }
         children += rectangle(150.0, 4).apply {
            translateX = 70.0
            translateY = 195.0
         }
         children += rectangle(150.0, 4).apply {
            translateX = 270.0
            translateY = 195.0
         }
      }
   }
}

private fun rectangle(length: Double, repeats: Int) = Rectangle(length, 3.0).apply {
   val stops = mutableListOf<Stop>(Stop(0.0, Color.GREEN), Stop(0.49, Color.GREEN), Stop(0.5, Color.ORANGERED))
   fill = LinearGradient(0.0, 0.0, length / repeats, 0.0, false, CycleMethod.REPEAT, stops)
}

fun main() {
   Application.launch(CrossHair::class.java)
}

当然是Kotlin。
与@James_D不同的是,LinearGradient宽度是通过使用Rectangle的长度和所需的重复次数来设置的。如果需要更改重复次数,则在Rectangle上放置一个扩展函数来重新计算LinearGradient将是微不足道的。
注意,只有大约3行代码做渐变的东西,其余的是布局。
对于缩放,我很想在整个窗格上进行缩放转换,并将其作为一个单位使用。
不管怎样,它看起来是这样的:

相关问题