首页 > 解决方案 > 当包含 Shape 的组的比例不是默认值时如何在 JavaFX 中绘制形状

问题描述

我正在学习如何在 JavaFX 中拖动鼠标时创建形状,并且可以在拖动鼠标时创建形状,但是当我更改包含该形状的scaleXandscaleY时会出现问题。Group问题是,当我尝试在比例不是 1 时创建形状时,当我在代码中编写根据鼠标位置设置它的平移值时,形状的位置会更改事件。我曾多次尝试解决此问题,但我无法弄清楚为什么会发生这种情况或如何解决此问题。

这是我的代码:

我正在使用代码来修改在拖动鼠标时Rectangle调用的代码,object但是当我拖动鼠标保持比例不是 1 时,它的位置正在移动。再次澄清,我试图在拖动鼠标时创建矩形。但它的位置不是鼠标所在的位置,即当组的比例不是1时位置会移动。

import javafx.application.Application;
import javafx.geometry.Bounds;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class Example extends Application{
    
    private Group  group;
    private double mousePointX;
    private double mousePointY;
    
    public static void main(String... arguments){ launch(arguments); }
    
    @Override public void start(Stage primaryStage){
        
        group = new Group();
        
        Pane pane = new Pane(group);
        pane.setOnMousePressed(this::recordPosition);
        pane.setOnMouseDragged(this::makeShape);
        pane.setOnScroll(this::handleScroll);
        
        primaryStage.setScene(new Scene(new BorderPane(pane)));
        primaryStage.show();
    }
    
    //record mouse position
    private void recordPosition(MouseEvent event){
        mousePointX = event.getX();
        mousePointY = event.getY();
    }
    
    //method to make shape
    private void makeShape(MouseEvent event){
        Rectangle object;
        object = new Rectangle(200, 200, Color.BLUE);
        object.setStroke(Color.BLACK);
    
        group.getChildren().addAll(object);
        
        object.setTranslateX(mousePointX - group.getTranslateX());
        object.setTranslateY(mousePointY - group.getTranslateY());
        object.setHeight(event.getY() - mousePointY);
        object.setWidth(event.getX() - mousePointX);
    }
    
    //method to control scroll
    private void handleScroll(ScrollEvent event){
        if(event.isControlDown()){
            zoom(Math.pow(1.01, event.getDeltaY()), event.getSceneX(), event.getSceneY());
        }else{
            group.setTranslateX(this.group.getTranslateX() + event.getDeltaX());
            group.setTranslateY(this.group.getTranslateY() + event.getDeltaY());
        }
        event.consume();
    }
    
    //method to control zoom
    private void zoom(double factor, double x, double y){
        double oldScale = group.getScaleX();
        double scale    = oldScale * factor;
        
        if(scale < 0.05) scale = 0.05;
        if(scale > 50) scale = 50;
        
        group.setScaleX(scale);
        group.setScaleY(scale);
        
        double f      = (scale / oldScale) - 1;
        Bounds bounds = this.group.localToScene(this.group.getBoundsInLocal());
        double dx     = (x - (bounds.getWidth() / 2 + bounds.getMinX()));
        double dy     = (y - (bounds.getHeight() / 2 + bounds.getMinY()));
        
        group.setTranslateX(this.group.getTranslateX() - f * dx);
        group.setTranslateY(this.group.getTranslateY() - f * dy);
    }
    
}

那么,当包含该形状的组的比例不是 1 时,绘制形状的正确方法是什么?

请建议我。

标签: javajavafxjavafx-11

解决方案


不是最干净的方式,但仍然是一种方式,问题是很难计算 Scale 对您的团队的影响(如果有人知道怎么做会很棒),所以我绕过它:

import javafx.application.Application;
import javafx.geometry.Bounds;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

import java.util.ArrayList;
import java.util.List;

public class MySolution extends Application{

    List<Group> groups = new ArrayList<>();
    private Group  group;
    private Rectangle object ;
    private Pane pane;
    private double mousePointX;
    private double mousePointY;

    public static void main(String... arguments){ launch(arguments); }

    @Override public void start(Stage primaryStage){

        group = new Group();

        pane = new Pane(group);
        pane.setOnMousePressed(this::recordPosition);
        pane.setOnMouseDragged(this::makeShape);
        pane.setOnScroll(this::handleScroll);

        primaryStage.setScene(new Scene(new BorderPane(pane)));
        primaryStage.show();
    }

    //record mouse position
    private void recordPosition(MouseEvent event){
        mousePointX = event.getX();
        mousePointY = event.getY();
        object = new Rectangle(0, 0, Color.BLUE);
        object.setStroke(Color.BLACK);
        group.getChildren().addAll(object);
    }

    //method to make shape
    private void makeShape(MouseEvent event){
        if(object!=null){
            object.setTranslateX(mousePointX - group.getTranslateX());
            object.setTranslateY(mousePointY - group.getTranslateY());
            object.setHeight(event.getY() - mousePointY);
            object.setWidth(event.getX() - mousePointX);
        }
    }

    //method to control scroll
    private void handleScroll(ScrollEvent event){
        if(event.isControlDown()){
            zoom(Math.pow(1.01, event.getDeltaY()), event.getSceneX(), event.getSceneY());
        }else{
            group.setTranslateX(this.group.getTranslateX() + event.getDeltaX());
            group.setTranslateY(this.group.getTranslateY() + event.getDeltaY());
            for (Group g:groups) {
                g.setTranslateX(g.getTranslateX() + event.getDeltaX());
                g.setTranslateY(g.getTranslateY() + event.getDeltaY());
            }
        }
        event.consume();
    }

    //method to control zoom
    private void zoom(double factor, double x, double y){
        groups.add(group);
        for (Group g:groups) {
            double oldScale = g.getScaleX();
            double scale    = oldScale * factor;
            if(scale < 0.05) scale = 0.05;
            if(scale > 50) scale = 50;
            g.setScaleX(scale);
            g.setScaleY(scale);
            double f      = (scale / oldScale) - 1;
            Bounds bounds = g.localToScene(g.getBoundsInLocal());
            double dx     = (x - (bounds.getWidth() / 2 + bounds.getMinX()));
            double dy     = (y - (bounds.getHeight() / 2 + bounds.getMinY()));
            g.setTranslateX(g.getTranslateX() - f * dx);
            g.setTranslateY(g.getTranslateY() - f * dy);
        }
        group = new Group();
        pane.getChildren().add(group);
    }

}

推荐阅读