AnchorPane Constraints in percentages - java

I am working on a project and I need you help.
I want to know that is this possible to set anchorpane constraints in percentage as something like
AnchorPane.setLeftAnchor(content1, 35%);

Yes it can be by updating constraint values on every scene size change:
public class AnchorDemo extends Application {
private final Button button = new Button("Add");
private final ListView list = new ListView();
#Override
public void start(Stage primaryStage) {
AnchorPane root = new AnchorPane();
AnchorPane.setTopAnchor(list, 10.0);
AnchorPane.setLeftAnchor(list, 10.0);
AnchorPane.setTopAnchor(button, 10.0);
AnchorPane.setRightAnchor(button, 10.0);
root.getChildren().addAll(list, button);
Scene scene = new Scene(root, 300, 250);
scene.widthProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
updateWidthConstaints(newValue.doubleValue());
}
});
primaryStage.setScene(scene);
primaryStage.show();
updateWidthConstaints(scene.getWidth());
}
private void updateWidthConstaints(double width) {
// roughly give to the list 66% while to the button 33% of available
// space, besides paddings.
// +5s are for extra padding
AnchorPane.setRightAnchor(list, width * 1 / 3 + 5);
AnchorPane.setLeftAnchor(button, width * 2 / 3 + 5);
}
public static void main(String[] args) {
launch(args);
}
}

Related

Javafx: Dialog y position doesn't work properly

Please, consider the following code:
public class JavaFxTest4 extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
Button button = new Button();
button.setText("dialog");
button.setOnAction((e) -> {
Dialog<?> d = new Dialog<>();
final Window window = d.getDialogPane().getScene().getWindow();
Stage stage = (Stage) window;
stage.setMinHeight(450);
stage.setMaxHeight(450);
stage.setHeight(450);
stage.setMinWidth(600);
stage.setMaxWidth(600);
stage.setWidth(600);
window.setY(300); //<---- note this line
window.setX(660); //<---- note this line
d.showAndWait();
});
VBox root = new VBox();
root.getChildren().addAll(button);
var scene = new Scene(root, 1920, 1000);
primaryStage.setScene(scene);
primaryStage.show();
}
}
As you can see window position is 660 (x) and 300 (y). And this is the result:
As you can see x position is correct, but y position is not. Is this a bug or I misunderstand something? I use javafx 19-ea+3 and openjdk version "14.0.2" on Ubuntu 20.
It is a bug in JavaFX. Issue is here

Can't drop a rectangle at the desired location with JavaFX

I am trying to implement a full press-drag-release gesture with JavaFX. I want to drag a rectangle from one VBox to another. On the MOUSE_DRAG_RELEASED event that happens on the target VBox, I'm trying to add the dragged rectangle as a child of the target VBox.
The problem is that when I release the mouse on the target VBox, the rectangle does not get into the expected position inside the VBox, but is always offset to the right by a fixed distance.
public class DragFromOneVBoxToAnother extends Application {
private Disk sourceDisk = new Disk();
private VBox targetVBox = new VBox();
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage stage) {
// Build the UI
GridPane root = getUI();
// Add the event handlers
this.addEventHandlers();
Scene scene = new Scene(root, 800, 600);
stage.setScene(scene);
stage.show();
}
private GridPane getUI() {
GridPane pane = new GridPane();
VBox sourceVBox = new VBox();
sourceDisk.setWidth(90);
sourceDisk.setHeight(20);
sourceVBox.setStyle(" -fx-border-color:red; -fx-border-width: 1; -fx-border-style: solid;");
targetVBox.setStyle(" -fx-border-color:green; -fx-border-width: 1; -fx-border-style: solid;");
sourceVBox.getChildren().add(sourceDisk);
targetVBox.getChildren().add(new Rectangle(200, 20));
pane.setHgap(200);
pane.addColumn(0, sourceVBox);
pane.addColumn(1, targetVBox);
pane.setPadding(new Insets(200, 100, 200, 100));
return pane;
}
private void addEventHandlers() {
sourceDisk.setOnMouseEntered(event -> sourceDisk.setCursor(Cursor.HAND));
sourceDisk.setOnMousePressed(event -> {
sourceDisk.setOrgSceneX(event.getSceneX());
sourceDisk.setOrgSceneY(event.getSceneY());
sourceDisk.setOrgTranslateX(sourceDisk.getTranslateX());
sourceDisk.setOrgTranslateY(sourceDisk.getTranslateY());
sourceDisk.setMouseTransparent(true);
sourceDisk.setCursor(Cursor.CLOSED_HAND);
});
sourceDisk.setOnDragDetected(event -> sourceDisk.startFullDrag());
sourceDisk.setOnMouseDragged(event -> {
double offsetX = event.getSceneX() - sourceDisk.getOrgSceneX();
double offsetY = event.getSceneY() - sourceDisk.getOrgSceneY();
double newTranslateX = sourceDisk.getOrgTranslateX() + offsetX;
double newTranslateY = sourceDisk.getOrgTranslateY() + offsetY;
sourceDisk.setTranslateX(newTranslateX);
sourceDisk.setTranslateY(newTranslateY);
});
sourceDisk.setOnMouseReleased(event -> {
sourceDisk.setMouseTransparent(false);
sourceDisk.setCursor(Cursor.DEFAULT);
});
targetVBox.setOnMouseDragReleased(event ->
targetVBox.getChildren().add(sourceDisk));
}
private class Disk extends Rectangle {
private double orgSceneX;
private double orgSceneY;
private double orgTranslateX;
private double orgTranslateY;
// below, the getters and setters for all the instance variables
// were removed for brevity
}
I have found that, even though the visual representation of the dragged rectangle seems to be offset when it's dropped, a child appears to actually be added to the target VBox (this can be seen because the border of the VBox expands after the MOUSE_DRAG_RELEASED event).
What could be the issue?
During the mouse drag gesture you modify the translateX/translateY properties of the node. This results in the dragged node being offset from the position where the new parent places it by this transformation. You need to reset those values to properly add the node to the bottom of the VBox:
targetVBox.setOnMouseDragReleased(event -> {
targetVBox.getChildren().add(sourceDisk);
// reset translate values
sourceDisk.setTranslateX(0);
sourceDisk.setTranslateY(0);
});

JavaFX CheckBoxTreeItem graphic disappear/appear when expanding/collapsing

I'm trying to make TreeView with CheckBoxTreeItems. When I collapse/expand a CheckBoxTreeItems the image I set up does not display correctly. I googled but I couldn't find correct answer. On Stack Overflow, I found a similar problem, but I didn't get a valid answer.
E.g
JavaFX CheckBoxTreeItem graphic disappear when siblings collapse
JavaFX CheckBoxTreeItem: Graphic disappears if graph is extended
Any ideas?
public class ClientApplication extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(final Stage stage) {
ImageView folderIcon = new ImageView();
Image folderImage = new Image("image/folder.png");
folderIcon.setImage(folderImage);
folderIcon.setFitWidth(16);
folderIcon.setFitHeight(16);
CheckBoxTreeItem<String> rootItem = new CheckBoxTreeItem<String>("folder", folderIcon);
rootItem.setExpanded(true);
for (int i = 0; i < 4; i++) {
CheckBoxTreeItem<String> checkBoxTreeItem = new CheckBoxTreeItem<String>("Sample" + (i + 1), folderIcon);
rootItem.getChildren().add(checkBoxTreeItem);
}
final TreeView<String> tree = new TreeView<String>(rootItem);
tree.setCellFactory(CheckBoxTreeCell.<String>forTreeView());
tree.setRoot(rootItem);
tree.setShowRoot(true);
StackPane root = new StackPane();
root.getChildren().add(tree);
stage.setScene(new Scene(root, 300, 250));
stage.show();
}
}
enter image description here
I tried to use the ideas provided by #Jai,But when I click the expand/collapse icon, there is still a problem.Attachment is a screenshot.Thanks in advance.
enter image description here
ImageView is a JavaFX control. This means that each instance represents a unique control you see on your screen. You should never use the same instance for multiple locations in your GUI.
On the other hand, Image represents an image (i.e. an array of pixel data), so it is reusable.
This should work:
#Override
public void start(final Stage stage) {
final Image folderImage = new Image("image/folder.png");
CheckBoxTreeItem<String> rootItem = new CheckBoxTreeItem<String>("folder", createImageView(folderImage));
rootItem.setExpanded(true);
for (int i = 0; i < 4; i++) {
CheckBoxTreeItem<String> checkBoxTreeItem = new CheckBoxTreeItem<String>("Sample" + (i + 1), createImageView(folderImage));
rootItem.getChildren().add(checkBoxTreeItem);
}
final TreeView<String> tree = new TreeView<String>(rootItem);
tree.setCellFactory(CheckBoxTreeCell.<String>forTreeView());
tree.setRoot(rootItem);
tree.setShowRoot(true);
StackPane root = new StackPane();
root.getChildren().add(tree);
stage.setScene(new Scene(root, 300, 250));
stage.show();
}
private ImageView createImageView(Image folderImage) {
ImageView folderIcon = new ImageView();
folderIcon.setImage(folderImage);
folderIcon.setFitWidth(16);
folderIcon.setFitHeight(16);
return folderIcon;
}

Listen for transformation changes

Is there way to listen for transformation changes? I'd like to get notified when for example a cube has turned. Especially I'am interested in getLocalToSceneTransform.
Here is my try:
#Override
public void start(Stage primaryStage) throws Exception {
final Group root = new Group();
final Scene scene = new Scene(root);
final Box cube = new Box(1, 1, 1);
cube.setRotationAxis(Rotate.Y_AXIS);
cube.setMaterial(new PhongMaterial(Color.RED));
root.getChildren().add(cube);
cube.getLocalToSceneTransform().addEventHandler(TransformChangedEvent.TRANSFORM_CHANGED, (e) -> {
// never get called
System.out.println("Transformation has changed");
});
final Camera camera = new PerspectiveCamera(true);
camera.setTranslateZ(-4);
scene.setCamera(camera);
final Timeline turnCube = new Timeline();
turnCube.getKeyFrames().add(new KeyFrame(Duration.seconds(0), new KeyValue(cube.rotateProperty(), 0)));
turnCube.getKeyFrames().add(new KeyFrame(Duration.seconds(5), new KeyValue(cube.rotateProperty(), 360)));
turnCube.setCycleCount(Timeline.INDEFINITE);
turnCube.play();
primaryStage.setWidth(1024);
primaryStage.setHeight(768);
primaryStage.setScene(scene);
primaryStage.show();
}
While the cube is turned the EventHandler get never called.
You can add a changeListener to the cube's localToSceneTransformProperty() to get notified when the cube is rotated.
cube.localToSceneTransformProperty().addListener((value, oldValue, newValue) -> {
System.out.println("Transformation has changed");
});

JavaFx keep window size after user resizes

I currently use the following code to switch between scenes. I want to switch between windows and KEEP the window size (so when the users change the windows size manually by resizing the window, it will stay at the chosen size even after scene change).
Scene scene = new Scene(pane); // new Scene(pane, userChosenWidth??, userChosenHeight??);
stage.setScene(scene);
stage.sizeToScene();
Does anyone know how to accomplish this?
Just call getWidth() and getHeight() on the current Scene. If you don't have a reference to the current scene, you can get one with stage.getScene().
Setting width and height in Stage worked for me.
double prevWidth = stage.getWidth();
double prevHeight = stage.getHeight();
stage.setScene(scene);
stage.setHeight(prevHeight);
stage.setWidth(prevWidth);
I created this class:
public class AppSize {
private static final String HEIGHT = "Height";
private static final String WIDTH = "Width";
private static final String Y = "Y";
private static final String X = "X";
private final static Preferences prefs = Preferences.userNodeForPackage(AppSize.class);
public static void setSize(Stage stage) {
Optional.ofNullable(prefs.getDouble(X, -1)).filter(x->x>=0).ifPresent(stage::setX);
Optional.ofNullable(prefs.getDouble(Y, -1)).filter(y->y>=0).ifPresent(stage::setY);
Optional.ofNullable(prefs.getDouble(WIDTH, -1)).filter(width->width>=0).ifPresent(stage::setWidth);
Optional.ofNullable(prefs.getDouble(HEIGHT, -1)).filter(height->height>=0).ifPresent(stage::setHeight);
stage.setOnCloseRequest(
e->{
if(stage.isFullScreen()) {
return;
}
prefs.putDouble(X, stage.getX());
prefs.putDouble(Y, stage.getY());
prefs.putDouble(WIDTH, stage.getWidth());
prefs.putDouble(HEIGHT, stage.getHeight());
});
}
}
its use:
public class App extends Application {
#Override
public void start(Stage stage) {
var label = new Label("AppSize test.");
var scene = new Scene(new StackPane(label), 640, 480);
stage.setScene(scene);
AppSize.setSize(stage);
stage.show();
}
public static void main(String[] args) {
launch();
}
}

Categories