Привязка свойств к точкам многоугольника в JavaFX

#javafx #resize #polygon #points #property-binding

#javafx #изменение размера #многоугольник #Очки #привязка свойств

Вопрос:

В следующем примере я связал серый прямоугольник с панелью по высоте и ширине. Синий многоугольник должен соответствовать прямоугольнику пропорционально. Это означает, что границы прямоугольника и многоугольника должны иметь одинаковый размер при изменении размера окна.

Я думаю, я могу добиться этого с помощью метода .addListener (через widthProperty и heightProperty) прямоугольника. Но мне это не удалось.

 import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class PolygonFunktion extends Application {

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

    @Override
    public void start(Stage stage) throws Exception {

        Pane pane = new Pane();
        
        //Rectangle
        Rectangle rec = new Rectangle();
        rec.setFill(Color.GRAY);
        
        rec.layoutXProperty().set(20);
        rec.layoutYProperty().set(20);
        rec.widthProperty().bind(pane.widthProperty().subtract(rec.layoutXProperty().multiply(2)));
        rec.heightProperty().bind(pane.heightProperty().subtract(rec.layoutYProperty().multiply(2)));

        //Polygon
        Polygon poly = new Polygon();
        Double[] xy = {0.,0.,  0.,-10., 10.,-10., 10.,-20., 20.,-20., 20.,-30., 30.,-30., 30.,0. };
        poly.getPoints().addAll(xy);
        poly.setFill(Color.BLUE);
        
        poly.layoutXProperty().bind(rec.layoutXProperty());
        poly.layoutYProperty().bind(rec.layoutYProperty().add(rec.heightProperty()));
                
        rec.widthProperty().addListener( (o,oP,nP) -> {
            //... ?
        });
        
        rec.heightProperty().addListener( (o,oP,nP) -> {
            //... ?         
        }); 
        
        pane.getChildren().add(rec);
        pane.getChildren().add(poly);

        stage.setScene(new Scene(pane, 300, 300));
        stage.show();
    }
}
 

введите описание изображения здесь

Я не хочу использовать методы масштабирования, потому что край многоугольника также будет масштабироваться.

Комментарии:

1. Просто пересчитайте точки в каждом прослушивателе.

2. Большое вам спасибо. Приятно было знать, что я на правильном пути.

Ответ №1:

Вы можете просто обновить точки в прослушивателе. Обратите внимание, что, поскольку каждый слушатель выполняет одно и то же, вам нужен только один. Что-то вроде:

 final int numBars = 3 ;
ChangeListener<Number> recSizeListener = (obs, oldValue, newValue) -> {
    double width = rec.getWidth();
    double height = rec.getHeight();
    Double[] points = new Double[(numBars 1)*4];
    for (int i = 0 ; i <= numBars ; i  ) {
        // x values 
        points[i*4] = points[i*4 2] = i*width/numBars ;
        // y values
        points[i*4 1] = -i*height/numBars ;
        points[i*4 3] = -(i 1)*height/numBars ;
    }
    // fix last point:
    points[numBars*4 3] = height ;
    poly.getPoints().setAll(points);
};
rec.widthProperty().addListener(recSizeListener);
rec.heightProperty().addListner(recSizeListener);
 

Однако вместо использования привязок и прослушивателей, вероятно, здесь лучше использовать пользовательский Pane и переопределить layoutChildren() метод:

 import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class PolygonFunktion extends Application {

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

    @Override
    public void start(Stage stage) throws Exception {

        Rectangle rec = new Rectangle();
        rec.setFill(Color.GRAY);
        Polygon poly = new Polygon();
        poly.setFill(Color.BLUE);
        
        final int numBars = 3 ;

        Pane pane = new Pane(rec, poly) {

            final double margin = 20 ;

            @Override
            protected void layoutChildren() {
                double width = getWidth();
                double height = getHeight();
                Double[] points = new Double[(numBars 1)*4];
                rec.setX(margin);
                rec.setY(margin);
                double recWidth = width-2*margin ;
                double recHeight = height-2*margin ;
                rec.setWidth(recWidth);
                rec.setHeight(recHeight);

                for (int bar = 0 ; bar <= numBars ; bar  ) {
                    points[4*bar] = points[4*bar 2] = margin   bar*recWidth/numBars ;
                    points[4*bar 1] = recHeight   margin - bar*recHeight/numBars ;
                    points[4*bar 3] = recHeight   margin - (bar 1)*recHeight/numBars ;
                }
                points[4*numBars   3] = recHeight   margin ;
                
                poly.getPoints().setAll(points);
            }
        };

        stage.setScene(new Scene(pane, 300, 300));
        stage.show();
    }
}
 

Это гарантирует, что вычисления выполняются только один раз при каждом развертывании панели.

Ответ №2:

Хорошо, у меня есть решение, которое может быть непривлекательным, но оно работает.

 import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class PolygonFunktion extends Application {

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

    @Override
    public void start(Stage stage) throws Exception {

        Pane pane = new Pane();
        
        //Rectangle
        Rectangle rec = new Rectangle();
        rec.setFill(Color.GRAY);
        
        rec.layoutXProperty().set(20);
        rec.layoutYProperty().set(20);
        rec.widthProperty().bind(pane.widthProperty().subtract(rec.layoutXProperty().multiply(2)));
        rec.heightProperty().bind(pane.heightProperty().subtract(rec.layoutYProperty().multiply(2)));

        //Polygon
        Polygon poly = new Polygon();
        Double[] xy = {0.,0.,  0.,-10., 10.,-10., 10.,-20., 20.,-20., 20.,-30., 30.,-30., 30.,0. };
        
        poly.getPoints().addAll(xy);
        poly.setFill(Color.BLUE);
        
        poly.layoutXProperty().bind(rec.layoutXProperty());
        poly.layoutYProperty().bind(rec.layoutYProperty().add(rec.heightProperty()));
        
        
        double maxWidth = poly.getLayoutBounds().getWidth(); 
        double maxHeight =  poly.getLayoutBounds().getHeight();

        
        rec.widthProperty().addListener( (o,oP,nP) -> { 
            
            for(int i=0;  i<poly.getPoints().size(); i =2) { 
                double polfac = xy[i] / maxWidth;               
                poly.getPoints() .set(i, polfac*nP.doubleValue());
            }  
        });
        
        rec.heightProperty().addListener( (o,oP,nP) -> { 
            
            for(int i=1;  i<poly.getPoints().size(); i =2) { 
                double polfac = xy[i] / maxHeight;
                poly.getPoints() .set(i, polfac*nP.doubleValue());
            }  
        }); 
        
        pane.getChildren().add(rec);
        pane.getChildren().add(poly);

        stage.setScene(new Scene(pane, 300, 300));
        stage.show();
    }
}