Resultados de operaciones de escala y traducción de JavaFX en anomalías

Tengo un Panel (test_) como elemento secundario central de un panel de borde. El niño llena su área y crece cuando la ventana se estira como se esperaba.

Ahora escalo test_. Normalmente estaría centrado en su área, pero no quiero eso, así que lo traduzco de vuelta a la esquina superior izquierda de su área.

Pero ahora, cuando estiro la viuda, tira de test_ lejos de la esquina superior izquierda de su área. ¿Alguien puede explicar por qué sucede esto? El siguiente ejemplo incorpora un control deslizante que escala test_.

Gracias por su atención.

package fxuicontrols;

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Bounds;
import javafx.scene.Scene;
import javafx.scene.control.Slider;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class ScaleTest
    extends Application
    implements ChangeListener<Number>
{
    private final Pane  test_    = new Pane();

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

    @Override
    public void start(Stage stage) throws Exception
    {
        test_.setStyle( "-fx-background-color: blue;" );

        Text    text    = new Text( "Upper left corner" );
        text.setFill( Color.WHITE );
        text.relocate( 0, 0 );
        test_.getChildren().add( text  );

        final Slider    scaler  = new Slider( .25, 1, 1 );
        scaler.valueProperty().addListener( this );
        test_.scaleXProperty().bind( scaler.valueProperty() );
        test_.scaleYProperty().bind( scaler.valueProperty() );

        BorderPane  root    = new BorderPane();
        root.setPrefSize( 250, 250 );
        root.setCenter( test_ );
        root.setBottom( scaler );

        stage.setScene( new Scene( root ) );
        stage.show();
    }

    @Override
    public void
    changed( ObservableValue<? extends Number> oVal,
                Number oldNm,
                Number newNum
    )
    {
        double  scale   = newNum.doubleValue();
        Bounds  bounds  = test_.getLayoutBounds();
        double  width   = bounds.getWidth();
        double  height  = bounds.getHeight();
        test_.setTranslateX( (scale * width - width) / 2 );
        test_.setTranslateY( (scale * height - height) / 2 );
    }
}

preguntado el 22 de mayo de 12 a las 19:05

1 Respuestas

La razón por la que su solución falla cuando se cambia el tamaño de la escena es porque los paneles son nodos de tamaño variable, por lo que los límites de diseño del panel cambian a medida que se cambia el tamaño del panel, pero no lo tiene en cuenta en sus cálculos de traducción.

Lo siguiente usa directamente transformaciones Scale and Translate para evitar cualquier problema relacionado con el cambio de tamaño. ¿Este código de muestra hace lo que quieres?

import javafx.application.Application;
import javafx.beans.value.*;
import javafx.geometry.*;
import javafx.scene.Scene;
import javafx.scene.control.Slider;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.scene.transform.*;
import javafx.stage.Stage;

// demonstrates scaling a test pane with content in it.
// slide the slider at the bottom of the scene around to shrink and grow the content.
public class ScaleTest extends Application {
  public static void main(String[] args) { launch(); }
  @Override public void start(Stage stage) throws Exception {
    // create a test pane for scaling.
    Pane testPane = new Pane();
    // make the test pane background a different color if you want to see the extent of the pane.
    testPane.setStyle("-fx-background-color: blue;");

    // create some text content to place in the test pane.
    Text text = new Text("Upper left corner");
    text.setStyle("-fx-font-size: 30px;");
    text.setFill(Color.WHITE);
    text.setTextOrigin(VPos.TOP);
    testPane.getChildren().add(text);
    Scale scaleTransform = new Scale();
    testPane.getTransforms().addAll(scaleTransform, new Translate(0, 0));

    // slider to scale the test pane.
    final Slider scaler = new Slider(.25, 3, 1);
    scaleTransform.xProperty().bind(scaler.valueProperty());
    scaleTransform.yProperty().bind(scaler.valueProperty());

    // stackpane added to pad out empty space when testPane is scaled small.
    // stackpane also clips the zoomed content when it gets larger than it's standard layout.
    final StackPane stack = new StackPane();
    stack.getChildren().addAll(testPane);
    StackPane.setAlignment(testPane, Pos.TOP_LEFT);
    stack.setStyle("-fx-background-color: blue;");

    final Rectangle clip = new Rectangle();
    testPane.layoutBoundsProperty().addListener(new ChangeListener<Bounds>() {
      @Override public void changed(ObservableValue<? extends Bounds> observable, Bounds oldBounds, Bounds bounds) {
        clip.setWidth(bounds.getWidth());
        clip.setHeight(bounds.getHeight());
      }
    });
    stack.setClip(clip);

    // layout everything.
    VBox layout = new VBox();
    layout.setPrefSize(250, 250);
    layout.getChildren().setAll(stack, scaler);
    VBox.setVgrow(stack, Priority.ALWAYS);

    // show the stage.
    stage.setScene(new Scene(layout));
    stage.show();
  }
}

contestado el 30 de mayo de 13 a las 11:05

No lo sé con certeza (y me temo que no lo sabré por un par de días), pero ciertamente parece intrigante. Gracias. - jack straub

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.