【问题标题】:Draw an arrow shape in javafx在javafx中绘制箭头形状
【发布时间】:2019-10-23 12:43:04
【问题描述】:

我想画一条带箭头的线(描绘箭头形状)。我提到了一个解决方案:JavaFX - draw line with arrow (Canvas)

上面的解决方案不允许箭头可以拖动,所以我写了一个小代码来使这个可以拖动

void drawArrow(int x1, int y1, int x2, int y2) {
        gc.clearRect(0, 0,drawingCanvas.getWidth(), drawingCanvas.getHeight());
        gc.setFill(Color.BLACK);
        double dx = x2 - x1, dy = y2 - y1;
        double angle = Math.atan2(dy, dx);
        int len = (int) Math.sqrt(dx * dx + dy * dy);
        Transform transform = Transform.translate(x1, y1);
        transform = transform.createConcatenation(Transform.rotate(Math.toDegrees(angle), 0, 0));
        gc.setTransform(new Affine(transform));
        gc.strokeLine(0, 0, len, 0);

        gc.fillPolygon(new double[]{len, len - ARR_SIZE, len - ARR_SIZE, len}, new double[]{0, -ARR_SIZE, ARR_SIZE, 0},
                4);
    }


        gc=drawingCanvas.getGraphicsContext2D();
        drawingCanvas.setOnMousePressed( e -> {
            startX = prevX = currentX = (int)e.getX();
            startY = prevY = currentY = (int)e.getY();
            dragging = true;
            drawArrow(startX, startY, currentX, currentY);
        });
        drawingCanvas.setOnMouseDragged( e -> { 

              if (!dragging)
                    return;
                currentX = (int)e.getX();
                currentY = (int)e.getY();
             gc.clearRect(0,0,drawingCanvas.getWidth(),drawingCanvas.getHeight());
                if (startX == currentX || startY == currentY)
                    return;
                drawArrow(startX, startY, currentX, currentY);

            prevX = currentX;
            prevY = currentY;
        });
        drawingCanvas.setOnMouseReleased( e -> {
            dragging = false;
             if (startX == currentX || startY == currentY)
                    return;

                drawArrow(startX, startY, currentX, currentY);
                prevX = currentX;
                prevY = currentY;
        });

这里的问题是之前的箭头即使在使用后也没有被清除 gc.clearRect(0,0,drawingCanvas.getWidth(),drawingCanvas.getHeight());

这是正在发生的事情:

预期结果:

【问题讨论】:

  • this。每次时间轴循环时,Jewelsea 都会重置背景颜色。你应该做类似的事情。
  • 每当你需要一些可拖动的东西时,你应该问问自己 Canvas 是否是正确的选择。
  • 谢谢@Sedrick,但这个解决方案对我不起作用。
  • " 寻求调试帮助的问题(“为什么这段代码不起作用?”)必须包括所需的行为、特定的问题或错误以及在问题本身中重现它所需的最短代码。没有明确的问题陈述对其他读者没有用处。请参阅:minimal reproducible example。"
  • @Nirman 是的,当然。您可以使用使用 Shapes 表示图形对象的场景图,并且因为它们也是节点,您可以将鼠标侦听器附加到它们并移动它们,而无需手动清除和重新绘制。

标签: javafx


【解决方案1】:

这是我的 Arrow 课程。我将其坐标绑定到可拖动的顶点(按钮)。

Dragged Arrows Example GIF

package mycontrols;

import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.collections.ListChangeListener;
import javafx.scene.Group;
import javafx.scene.shape.Polyline;

public class Arrow extends Group {

    private Polyline mainLine = new Polyline();
    private Polyline headA = new Polyline();
    private Polyline headB = new Polyline();
    private SimpleDoubleProperty x1 = new SimpleDoubleProperty();
    private SimpleDoubleProperty y1 = new SimpleDoubleProperty();
    private SimpleDoubleProperty x2 = new SimpleDoubleProperty();
    private SimpleDoubleProperty y2 = new SimpleDoubleProperty();
    private SimpleBooleanProperty headAVisible = new SimpleBooleanProperty(true);
    private SimpleBooleanProperty headBVisible = new SimpleBooleanProperty(true);
    private final double ARROW_SCALER = 20;
    private final double ARROWHEAD_ANGLE = Math.toRadians(20);
    private final double ARROWHEAD_LENGTH = 10;

    public Arrow(double x1, double y1, double x2, double y2){
        this.x1.set(x1);
        this.y1.set(y1);
        this.x2.set(x2);
        this.y2.set(y2);

        getChildren().addAll(mainLine, headA, headB);

        for(SimpleDoubleProperty s : new SimpleDoubleProperty[]{this.x1,this.y1,this.x2,this.y2}){
            s.addListener( (l,o,n) -> update() );
        }

        setUpStyleClassStructure();


        headA.visibleProperty().bind(headAVisible);
        headB.visibleProperty().bind(headBVisible);
        update();
    }

    private void setUpStyleClassStructure() {
        mainLine.getStyleClass().setAll("arrow");
        headA.getStyleClass().setAll("arrow");
        headB.getStyleClass().setAll("arrow");

        headA.getStyleClass().add("arrowhead");
        headB.getStyleClass().add("arrowhead");

        getStyleClass().addListener( (ListChangeListener<? super String>) c -> {
            c.next();
            for(Polyline p : new Polyline[]{mainLine, headA, headB}){
                p.getStyleClass().addAll(c.getAddedSubList());
                p.getStyleClass().removeAll(c.getRemoved());
            }
        });
    }

    private void update() {
        double[] start = scale(x1.get(), y1.get(), x2.get(), y2.get());
        double[] end = scale(x2.get(), y2.get(), x1.get(), y1.get());

        double x1 = start[0];
        double y1 = start[1];
        double x2 = end[0];
        double y2 = end[1];

        mainLine.getPoints().setAll(x1,y1,x2,y2);

        double theta = Math.atan2(y2-y1, x2-x1);

        //arrowhead 1
        double x = x1 + Math.cos(theta + ARROWHEAD_ANGLE) * ARROWHEAD_LENGTH;
        double y = y1 + Math.sin(theta + ARROWHEAD_ANGLE) * ARROWHEAD_LENGTH;
        headA.getPoints().setAll(x,y,x1,y1);
        x = x1 + Math.cos(theta - ARROWHEAD_ANGLE) * ARROWHEAD_LENGTH;
        y = y1 + Math.sin(theta - ARROWHEAD_ANGLE) * ARROWHEAD_LENGTH;
        headA.getPoints().addAll(x,y);
        //arrowhead 2
        x = x2 - Math.cos(theta + ARROWHEAD_ANGLE) * ARROWHEAD_LENGTH;
        y = y2 - Math.sin(theta + ARROWHEAD_ANGLE) * ARROWHEAD_LENGTH;
        headB.getPoints().setAll(x,y,x2,y2);
        x = x2 - Math.cos(theta - ARROWHEAD_ANGLE) * ARROWHEAD_LENGTH;
        y = y2 - Math.sin(theta - ARROWHEAD_ANGLE) * ARROWHEAD_LENGTH;
        headB.getPoints().addAll(x,y);
    }

    private double[] scale(double x1, double y1, double x2, double y2){
        double theta = Math.atan2(y2-y1, x2-x1);
        return new double[]{
                x1 + Math.cos(theta) * ARROW_SCALER,
                y1 + Math.sin(theta) * ARROW_SCALER
        };
    }

    //getters and setters
    public double getX1() {
        return x1.get();
    }
    public SimpleDoubleProperty x1Property() {
        return x1;
    }
    public void setX1(double x1) {
        this.x1.set(x1);
    }
    public double getY1() {
        return y1.get();
    }
    public SimpleDoubleProperty y1Property() {
        return y1;
    }
    public void setY1(double y1) {
        this.y1.set(y1);
    }
    public double getX2() {
        return x2.get();
    }
    public SimpleDoubleProperty x2Property() {
        return x2;
    }
    public void setX2(double x2) {
        this.x2.set(x2);
    }
    public double getY2() {
        return y2.get();
    }
    public SimpleDoubleProperty y2Property() {
        return y2;
    }
    public void setY2(double y2) {
        this.y2.set(y2);
    }
    public boolean isHeadAVisible() {
        return headAVisible.get();
    }
    public SimpleBooleanProperty headAVisibleProperty() {
        return headAVisible;
    }
    public void setHeadAVisible(boolean headAVisible) {
        this.headAVisible.set(headAVisible);
    }
    public boolean isHeadBVisible() {
        return headBVisible.get();
    }
    public SimpleBooleanProperty headBVisibleProperty() {
        return headBVisible;
    }
    public void setHeadBVisible(boolean headBVisible) {
        this.headBVisible.set(headBVisible);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多