Adjust JFXDialog to its StackPane - javafx

So I have this line of code which shows a Dialog:
public void showInfoDialog(String header,String message) {
JFXDialogLayout content = new JFXDialogLayout();
content.setHeading(new Text(header));
content.setBody(new Text(message));
JFXDialog dialog = new JFXDialog(mySP,content, JFXDialog.DialogTransition.CENTER);
dialog.setMinHeight(mySP.getPrefHeight());
dialog.setMinWidth(mySP.getPrefWidth());
JFXButton button = new JFXButton("OK");
button.setOnAction((ActionEvent event) -> {
dialog.close();
});
content.setActions(button);
dialog.show();
}
And that is leading to this output:
How can I adjust the height and width of the dialog so I can't see the grey background of my stackpane

You can just set a maximum size for the Dialog, or simply adjust the size of the stackPane you set for reference.
Try to add this to your code:
dialog.setMaxSize(100, 100); //For example
It'll just adjust the size of your stackPane and make it as the same size of your dialog.

Related

ScrollPane.setVvalue() does not update scrollbar in javafx

I have a program where I can insert something in a textfield and then after pressing the enter button, it will be displayed as a label in a VBox.
My layout looks like this:
A tab with inside a borderpane with on the bottom a hbox containing a textfield and a button and at the top a scrollpane containing a vbox full of labels.
This is the code:
Tab consoleTab = new Tab("Console");
consoleTab.setClosable(false);
BorderPane consoleContent = new BorderPane();
TextField commandEntry = new TextField();
commandEntry.setPromptText("Enter command...");
Button exe = new Button("Enter");
HBox input = new HBox(5, commandEntry, exe);
VBox outputL = new VBox();
ScrollPane output = new ScrollPane();
output.setMinHeight(365);
output.setMaxHeight(365);
output.setContent(outputL);
EventHandler<ActionEvent> customEvent = e -> {
String in = commandEntry.getText();
if (in.equals("")) return;
Label inserted = new Label("> "+in);
inserted.setStyle("-fx-font-weight: bold");
outputL.getChildren().add(inserted);
commandEntry.setText("");
Command cmd = new Command(in, outputL);
cmd.execute(true);
output.setVvalue(1); // This does not work
};
commandEntry.setOnAction(customEvent);
exe.setOnAction(customEvent);
consoleContent.setTop(output);
consoleContent.setBottom(input);
consoleContent.setPadding(new Insets(5, 5, 5, 5));
consoleTab.setContent(consoleContent);
And this is the Command.java class:
public class Command {
private String command;
private VBox vbox;
public static final String NEW_FILE = "new_file";
public static final String OPEN_FILE = "open";
public static final String SAVE_FILE = "save";
public static final String LIST_FILES = "list";
public static final String HELP = "help";
public Command(String command, VBox v){
this.command = command;
this.vbox = v;
}
public void execute(boolean layout){
String[] args = this.command.split(" ");
String cmd = args[0];
String outputText = "";
switch (cmd){
case NEW_FILE:
break;
case OPEN_FILE:
outputText = "File opened";
break;
case SAVE_FILE:
break;
case LIST_FILES:
outputText = "Files listed";
break;
case HELP:
outputText = "Available commands:\nOPEN: open <file-name>\nLIST: list";
break;
default:
outputText = "Command not found, type help to get the list of available commands";
break;
}
if (layout){
makeLayout(outputText);
}
}
private void makeLayout(String outputText){
this.vbox.getChildren().add(new Label(outputText));
}
}
The problem is that when I call the setVvalue(1.0) method of the scrollpane, this is not setting the scrollbar at the bottom.
I have tried with using output.setContent(outputL) before output.setVvalue(1.0) but nothing changes.
Thanks for any help
Generate a layout pass before setting the scroll value. To generate a layout pass see:
Get the height of a node in JavaFX (generate a layout pass)
// change the content of the scroll pane
// . . .
// generate a layout pass on the scroll pane.
scrollPane.applyCss();
scrollPane.layout();
// scroll to the bottom of the scroll pane.
scrollPane.setVvalue(scrollPane.getVmax());
Why this works
When the layout pass occurs, the vValue of the scroll pane will change to keep the currently visible area displayed rather than the new area. If you then set the vValue to the maximum value, it will change from the value calculated in the layout pass to the maximum value, scrolling the pane to the bottom of the visible content.
Sample code
This is just a code snippet to demonstrate the approach, not an executable application.
I did test the approach with the example code in the original question, and it worked fine.
public void start(Stage stage) {
VBox content = new VBox();
final ScrollPane scrollPane = new ScrollPane();
scrollPane.setContent(content);
Button append = new Button("Append");
append.setOnAction(e -> appendToScrollPane(scrollPane));
VBox layout = new VBox(scrollPane, append);
stage.setScene(new Scene(layout));
stage.show();
}
public void appendToScrollPane(ScrollPane scrollPane) {
// ... actions which add content to the scroll pane ...
// generate a layout pass on the scroll pane.
scrollPane.applyCss();
scrollPane.layout();
// scroll to the bottom of the scroll pane.
scrollPane.setVvalue(scrollPane.getVmax());
}

How to keep an unmanaged node position fixed when its width/height changes

In JavaFX how do I keep the location (x,y coords) of an unmanaged Node the same when the width/height of the node changes?
The node is unmanaged and laid out using: resizeRelocate. This is working well but sometimes the node changes height or width and I would like to keep the current x,y coords. i.e. the node changes size but doesn't move within the scene.
I've tried listening to the boundsInLocal property and checking for differences in the minY values but the node is still moving and calling resizeRelocate from within the boundsInLocal listener triggers another boundsInLocal update.
What would be the best way to resize and reposition the node so that I keep the x,y coords but can change the width/height?
Here's an example:
import javafx.scene.*;
import javafx.scene.layout.*;
import javafx.scene.control.*;
import javafx.stage.*;
import javafx.application.*;
public class SizeTest extends Application
{
public static void main (String[] args)
{
Application.launch (args);
}
#Override
public void start (Stage stage)
{
try
{
VBox b = new VBox ();
VBox other = new VBox ();
other.setManaged (false);
other.setPrefWidth (100);
other.setStyle ("-fx-border-width: 2px; -fx-border-color: red; -fx-padding: 5px;");
b.getChildren ().add (other);
VBox another = new VBox ();
another.setPrefWidth (50);
another.setMinHeight (50);
another.setPrefHeight (50);
another.setStyle ("-fx-background-color: blue;");
Button but = new Button ("Push Me");
but.setOnAction (ev ->
{
Button abut = new Button ("Another one");
other.getChildren ().add (abut);
});
other.getChildren ().addAll (another, but);
other.boundsInLocalProperty ().addListener ((p, oldv, newv) ->
{
double h = other.prefHeight (other.getPrefWidth ());
other.resizeRelocate (other.getBoundsInParent ().getMinX (),
other.getBoundsInParent ().getMinY (),
other.getBoundsInParent ().getWidth (),
h);
});
Scene sc = new Scene (b);
stage.setScene (sc);
stage.sizeToScene ();
stage.show ();
Platform.runLater (() ->
{
double h = other.prefHeight (other.getPrefWidth ());
other.resizeRelocate (100,
100,
other.getPrefWidth (),
h);
});
} catch (Exception e) {
e.printStackTrace ();
}
}
}
When you press the "Push Me" button another button is added to the container, it then overflows. I'd like the "other" container to instead resize itself to its preferred size but keep its x,y coords.
The listener for the boundsInLocal property sort of does this but you'll notice the jump in position and incorrect sizing. Removing the listener sizes and positions the node correctly but adding the new button overflows the container.
At this point I'm thinking of creating my own layout manager for this behavior.
My final solution to this was to use a javafx.scene.layout.Pane. My use case here was to have a number of popups appear above the content. I used a StackPane with the "popup pane" being the top level with a transparent background. The "popups" are added to the Pane and positioned with Node.relocate(x,y). The pane handles sizing and will keep the popup at the specified x,y coords. The pane keeps the popup at its preferred size so manual sizes changes should be made through the setPref* methods.
Addendum: while the above method works, because the popup pane would be a sibling of other children of the StackPane then events aren't delivered to the "lower levels", i.e. whatever is below the popup pane.
To get around this I added the content pane (the lower level) to the Pane and then tied the content pane's pref width/height to the size of the Pane.
i.e.
this.popupPane = new Pane ();
this.contentPane = new SplitPane ();
this.contentPane.prefWidthProperty ().bind (this.popupPane.widthProperty ());
this.contentPane.prefHeightProperty ().bind (this.popupPane.heightProperty ());
this.popupPane.getChildren ().add (this.contentPane);

How to add child node without affecting layout of GridPane parent

I want create a app using javafx. It looks like this:
I want to add the zoom function for the chart. When I click the button "Zoom in", the app will become fig2. However, I have no idea to achieve it. When I change the size of pane included the chart, it will change grid pane size, looks like this:
You do not want the zoom to be considered for the gridpane layout. In this can be achieved by applying transforms to the child of the gridpane you want to modify.
The following example demonstrates how to zoom a node while the mouse is hovering over it:
private static Region createRegion(String background) {
Region region = new Region();
region.setStyle("-fx-background-color:"+background);
region.setPrefSize(300, 100);
return region;
}
#Override
public void start(Stage primaryStage) {
GridPane gp = new GridPane();
// create background
gp.add(createRegion("green"), 0, 0);
gp.add(createRegion("dodgerblue"), 0, 1);
// create region to be zoomed
Region zoomRegion = createRegion("red");
GridPane.setFillWidth(zoomRegion, Boolean.FALSE);
GridPane.setFillHeight(zoomRegion, Boolean.FALSE);
zoomRegion.setPrefWidth(100);
Scale scale = new Scale();
zoomRegion.getTransforms().add(scale);
// keep pivot at bottom left corner
scale.pivotYProperty().bind(zoomRegion.heightProperty());
zoomRegion.hoverProperty().addListener((observable, oldValue, newValue) -> {
// adjust scale when hover state is changed
double scaleFactor = newValue ? 1.5 : 1;
scale.setX(scaleFactor);
scale.setY(scaleFactor);
});
gp.add(zoomRegion, 0, 1);
Scene scene = new Scene(gp);
primaryStage.setScene(scene);
primaryStage.show();
}

the size of sub node changes causing changes of parent node's size in javafx

For example, I use an imageview as the sub node of a vbox, when I change the size property(fitWidthProperty and fitHeightProperty), the size of box also changes. How can I stop this? There just do it like the code follows.But actually Vbox is the child of GridPane which I don't list it.
public int DEFAULT_WIDTH = 200;
//onAction means a click on button
public void onAction(){
changeDefaultWidth();
}
//initial another control ,just like pagination.
public void configureCellFactory(){
VBox box = new VBox();
ImageView imageView = new ImageView();
imageView.fitWidthProperty().bind(default_width);
box.getChildren().add(imageView);
}

JavaFX trouble with fade transitions

I'm currently developing an app. It's visual structure is the following:
Only one Stage.
Only one Scene which has an ApplicationContainer's (my own class which
is basically a StackPane with a BorderPane inside of it with a
MenuBar on top, and the current page in it's center).
Multiple ApplicationLayout's
The ApplicationLayout has a Header and a Footer (footer not implemented yet) and looks like this:
I've managed to implement fadeIn / fadeOut transitions between the pages by setting a StackPane as the BorderPane's center, adding the page to it, and on top of that, a white VBox. So before I make the page switch I work with FadeTransitions of this white VBox.
I had to do it this way because setOpacity() wouldn't change the textfields or button opacities for some reason.
Now I'm trying to do the exact same thing for the header. So I setted a StackPane to the top, and added to it the header and a on top of it a "header coverer" which supposedly should do the trick just as before (can't modify the opacity property of the title, arrow or description because of CSS overriding).
But this time it's not working, if I set the opacity of the header coverer to anything but 0, the stuff in the header doesn't show.
What I want to acomplish is to fadeOut / FadeIn the components of the header but not the orange HBox.
EDIT: Added a minimal example where this doesn't work for me
public class Main extends Application {
private Boolean buttonPressed = false;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
BorderPane appWindow = new BorderPane();
appWindow.setStyle("-fx-alignment: center; -fx-padding: 30 0 0 30");
appWindow.setBackground(new Background(new BackgroundFill(Color.PERU, null, null)));
GridPane loginContainer = new GridPane();
appWindow.setCenter(loginContainer);
TextField username = new TextField();
PasswordField password = new PasswordField();
Label userNameDesc = new Label("Username");
Label passwordDesc = new Label("Password");
Button logInBtn = new Button("Log In");
logInBtn.setTranslateX(100);
logInBtn.setTranslateY(20);
logInBtn.setOnAction(event -> {
if (!buttonPressed) {
appWindow.getCenter().setOpacity(30);
buttonPressed = true;
System.out.println("Opacity set to " + appWindow.getCenter().getOpacity());
}
else {
appWindow.getCenter().setOpacity(100);
buttonPressed = false;
System.out.println("Opacity set to " + appWindow.getCenter().getOpacity());
}
});
loginContainer.addColumn(0, userNameDesc, passwordDesc);
loginContainer.addColumn(1, username, password);
loginContainer.add(logInBtn, 1, 2);
Scene scene = new Scene(appWindow, 300, 250);
stage.setScene(scene);
stage.show();
}
}
Pressing the "Log In" button should affect the Gridpane and Gridpane childs visual opacity, but it doesn't. It just prints the correct opacity values.
According to the documentation:
Opacity is specified as a value between 0 and 1. Values less than 0 are treated as 0, values greater than 1 are treated as 1.
So setting the value to 30 or to 100 has no effect: both are treated as fully opaque (i.e. they are clamped at 1).
Replacing
appWindow.getCenter().setOpacity(30);
with
appWindow.getCenter().setOpacity(0.3);
will make the center content partially transparent.

Resources