#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();
}
}