I am new to Java Fx using Netbeans 7.3.1.I am experimenting new things with Gridpane and I just want to place a Gridpane in a another position other than the left topmost position of the window..The root.getChildren().add(gridpane); adds the gridpane to the topmost left corner of the window.. How can i place the Gridpane on another place of the window without adding any new child or root!!My root is just a group and the current code just overlaps the gridpane with the Menubar.. My full code is this!!
public class Menu extends Application {
#Override
public void start(Stage primaryStage){
Group root = new Group();
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
MenuBar menuBar = new MenuBar();
javafx.scene.control.Menu m = new javafx.scene.control.Menu("File");
m.getItems().add(new MenuItem("New"));
m.getItems().add(new SeparatorMenuItem());
m.getItems().add(new MenuItem("Exit"));
menuBar.getMenus().add(m);
javafx.scene.control.Menu tools = new javafx.scene.control.Menu("Cameras");
tools.getItems().add(CheckMenuItemBuilder.create()
.text("Show Camera 1")
.selected(false)
.build());
menuBar.getMenus().add(tools);
root.getChildren().add(menuBar);
GridPane gridpane = new GridPane();
gridpane.setPadding(new Insets(5));
gridpane.setHgap(5);
gridpane.setVgap(5);
Label fNameLbl = new Label("First Name");
TextField fNameFld = new TextField();
Label lNameLbl = new Label("First Name");
TextField lNameFld = new TextField();
Button saveButt = new Button("Save");
// First name label
GridPane.setHalignment(fNameLbl, HPos.RIGHT);
gridpane.add(fNameLbl, 0, 0);
// Last name label
GridPane.setHalignment(lNameLbl, HPos.RIGHT);
gridpane.add(lNameLbl, 0, 1);
// First name field
GridPane.setHalignment(fNameFld, HPos.LEFT);
gridpane.add(fNameFld, 1, 0);
// Last name field
GridPane.setHalignment(lNameFld, HPos.LEFT);
gridpane.add(lNameFld, 1, 1);
// Save button
GridPane.setHalignment(saveButt, HPos.RIGHT);
gridpane.add(saveButt, 1, 2);
root.getChildren().add(gridpane);
primaryStage.setScene(scene);
primaryStage.show();
}
try Scene Builder...it is used for designing javafx pages...
you can design all your pages according you need.
I'm not sure if it works but try using the following:
grid.setAlignment(Pos.CENTER);
Centre can be replaced with any other position as far as I am aware. I hope this helps somewhat.
Related
This question already has answers here:
Get the height of a node in JavaFX (generate a layout pass)
(2 answers)
Closed 8 years ago.
I am developing an application for which it is necessary to layout nodes besides each other (or on top of each other etc.). However, this layout is only an initial placement and the user is able to move these nodes arbitrarily. How is this done in the correct way in JavaFX? I will explain my problem with a simplified example:
Assume I have 2 rectangles and want to place rect2 to the right of rect1.
// create first rectangle at position x= 5, y=5
rect1 = rectangle(5,5);
// create second rectangle to the right of rect1
rect2 = rectangle(5+rect1.width(), 5);
In this scenario JavaFX will not yet have determined the width of rect1 and it will be zero. Intuitively, I would perform a call that lets JavaFX draw rect1 and thus determine its width and afterwards add rect2. See the following example:
// create first rectangle at position x= 5, y=5
rect1 = rectangle(5,5);
// let JavaFX draw rect1 (width will be calculated and set)
draw();
// create second rectangle to the right of rect1
rect2 = rectangle(5+rect1.width(), 5);
Unfortunately I haven't found a method that does what I want. My current workaround makes use of Platform.runLater() but this does not work properly all the time. If my understanding of bindings is correct, bindings are also not suitable for this problem. I only want to initially layout the nodes, so I would have to remove the binding after the initial layout (or else rect2 would move if rect1 is moved).
Thanks in advance for any help.
EDIT: Here is a minimal working example. The width of the button is 0. I tried calling root.layout() to force a layout pass etc. but it does not seem to work.
public class Test extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
Button btn = new Button();
StackPane root = new StackPane();
Scene scene = new Scene(root, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
btn.setText("Say 'Hello World'");
root.getChildren().add(btn);
// prints out 0
System.out.println(btn.getWidth());
}
}
Given the example from above, if I set the scene of the stage to null and then reset it, the button width will be set correctly when calling System.out.println(). It seems that this forces a layout pass on the whole stage? However, this just seems to be another workaround, in particular I have performance concerns.
#Override
public void start(Stage primaryStage) {
Button btn = new Button();
StackPane root = new StackPane();
Scene scene = new Scene(root, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
btn.setText("Say 'Hello World'");
root.getChildren().add(btn);
// reset scene
primaryStage.setScene(null);
primaryStage.setScene(scene);
// prints out 107.0
System.out.println(btn.getWidth());
}
I am currently experimenting with JavaFX's scene graph. I came across a strange problem that i can't really explain. Have a look at the following code:
final BorderPane bp1 = new BorderPane();
final Button button = new Button("CLICK ME");
Scene sc1 = new Scene(bp1,100,100);
bp1.setCenter(button);
stage1.setScene(sc1);
stage1.show();
Stage stage2 = new Stage();
final BorderPane bp2 = new BorderPane();
Scene sc2 = new Scene(bp2,100,100);
stage2.setScene(sc2);
stage2.setX(250);
stage2.show();
bp2.setCenter(button);
bp1.setCenter(button);
What i am trying to do here is to add a node (Button) to a Borderpane which lies within a scene on stage1. At the end of the code i try to add the node to a different scene(pane) on stage2. This actually works. But the last line does not. The button remains on stage2. The strange thing is that if i replace the borderpane with a gridpane, the code works as intended. Why does the borderpane behave different from the gridpane in this situation?
Another question which came to my mind in this case: I assume that there is exactly 1 scene graph per scene (or stage). Is that correct?
I guess you found a bug in the BorderPane implementation. The BorderPane has a bit of peculiar way how it manages its children. You can find the BorderPane implementation here. I suggest you file a bug report at the javafx jira
My testcase:
final BorderPane bp1 = new BorderPane();
final BorderPane bp2 = new BorderPane();
System.out.println("bp1 "+bp1);
System.out.println("bp2 "+bp2);
final Button button = new Button("CLICK ME");
button.parentProperty().addListener(new ChangeListener<Parent>() {
#Override
public void changed(ObservableValue<? extends Parent> observableValue, Parent parent, Parent parent2) {
System.out.println("changed");
System.out.println(button.getParent());
}
});
bp1.centerProperty().addListener(new InvalidationListener() {
#Override
public void invalidated(Observable observable) {
System.out.println("bp1 center invalidated ");
}
});
bp2.centerProperty().addListener(new InvalidationListener() {
#Override
public void invalidated(Observable observable) {
System.out.println("bp2 center invalidated ");
}
});
// bp1.centerProperty().addListener(new ChangeListener<Node>() {
// #Override
// public void changed(ObservableValue<? extends Node> observableValue, Node node, Node node2) {
// System.out.println("bp1 center changed "+node+" -> "+node2);
// }
// });
// bp2.centerProperty().addListener(new ChangeListener<Node>() {
// #Override
// public void changed(ObservableValue<? extends Node> observableValue, Node node, Node node2) {
// System.out.println("bp2 center changed "+node+" -> "+node2);
// }
// });
Scene sc1 = new Scene(bp1,100,100);
bp1.setCenter(button);
primaryStage.setScene(sc1);
primaryStage.show();
Stage stage2 = new Stage();
Scene sc2 = new Scene(bp2,100,100);
stage2.setScene(sc2);
stage2.setX(250);
stage2.show();
bp2.setCenter(button);
bp1.setCenter(button);
output:
bp1 BorderPane#48a80c67
bp2 BorderPane#10c66375
changed
BorderPane#48a80c67[styleClass=root]
bp1 center invalidated
changed
null
changed
BorderPane#10c66375[styleClass=root]
bp2 center invalidated
Explanation:
I found that bp1's center property is not invalidated and thus not updated when the button is added to the second scene. Adding a node to another scene should normally cause it to be removed from the previous scene. However, since BorderPane uses a peculiar way to hold its values (object properties for center, left and so on), after the button is added to the second scene, the button is not removed from the center property of the BorderPane. Setting the button a second time on the same BorderPane doesn't add the button to its children because it thinks that it is already set as the center node.
To your second question:
yes, only one scene graph per stage/scene.
I created Icon with Borderpane, image and text which I want to set as button icon.
#Override
public void start(Stage primaryStage)
{
final VBox vbox = new VBox();
// create 3 toggle buttons and a toogle group for them
ToggleButton tb1 = new ToggleButton();
tb1.setGraphic(newConnectionIcon());
ToggleButton tb2 = new ToggleButton();
ToggleButton tb3 = new ToggleButton();
final ToggleGroup group = new ToggleGroup();
tb1.setToggleGroup(group);
tb2.setToggleGroup(group);
tb3.setToggleGroup(group);
// select the first button to start with
group.selectToggle(tb1);
final Rectangle rect1 = new Rectangle(300, 300);
rect1.setFill(Color.DARKOLIVEGREEN);
final Rectangle rect2 = new Rectangle(300, 300);
rect2.setFill(Color.LAVENDER);
final Rectangle rect3 = new Rectangle(300, 300);
rect3.setFill(Color.LIGHTSLATEGREY);
tb1.setUserData(rect1);
tb2.setUserData(rect2);
tb3.setUserData(rect3);
group.selectedToggleProperty().addListener(new ChangeListener<Toggle>()
{
#Override
public void changed(ObservableValue<? extends Toggle> ov, Toggle toggle, Toggle new_toggle)
{
if (new_toggle == null)
{
}
else
{
vbox.getChildren().set(1, (Node) group.getSelectedToggle().getUserData());
}
}
});
HBox hBox = new HBox();
hBox.getChildren().addAll(tb1, tb2, tb3);
hBox.setPadding(new Insets(10, 10, 10, 10));
vbox.getChildren().addAll(hBox, (Node) group.getSelectedToggle().getUserData());
StackPane root = new StackPane();
root.getChildren().add(vbox);
Scene scene = new Scene(root, 800, 850);
primaryStage.setScene(scene);
primaryStage.show();
}
private static BorderPane newConnectionIcon() {
// Add background effect
DropShadow ds = new DropShadow();
ds.setOffsetY(2.0);
ds.setOffsetX(2.0);
ds.setColor(Color.GRAY);
// New BorderPane which will hold the components
bpi = new BorderPane();
bpi.setEffect(ds); // Add the effect
bpi.setCache(true);
// Set the size of the BorderPane
bpi.setPrefSize(30, 30);
bpi.setMaxSize(30, 30);
// Add style
bpi.setStyle("-fx-background-color: linear-gradient(#f2f2f2, #d4d4d4);"
+ " -fx-background-insets: 0 0 -1 0, 0, 1, 2;"
+ " -fx-background-radius: 3px, 3px, 2px, 1px;");
// Add Label to the Icon
Text inftx = new Text("New Connection");
inftx.setFont(Font.font ("Verdana", 5)); // Set font and font size
inftx.setFill(Color.WHITE); // Set font color
ncpic.setFitHeight(25); // Set size of the Icon picture
ncpic.setFitWidth(25);
// Internal StackPane which will hold the picture and the Icon Label
StackPane stack = new StackPane();
stack.getChildren().addAll(ncpic, inftx); // Add the picture and the Label
// Add the StackPane to the main BorderPane
bpi.setCenter(stack);
// Change the border of the Icon when the mouse is over the Icon
bpi = mouseOver(bpi);
// Navigate to new Panel when the user clicks on the Icon
bpi.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent t) {
}
});
return bpi;
}
How I can remove the default togglebutton and use the my custom icon as a button?
Use Labeled#setGraphic(Node). The ToggleButton is a Labeled and thus has the setGraphic(Node) method defined. Alternatively, you could use a specialized ToogleButton constructor too.
The argument you should pass to setGraphic() is your BorderPane! He is a Node =)
To be uber clear, here is a code snippet for you:
myToogleButton.setGraphic(myBorderPane);
I have this simple example of JavaFX tabs
primaryStage.setTitle("Tabs Test");
Group root = new Group();
Scene scene = new Scene(root, 600, 500, Color.WHITE);
TabPane tabPane = new TabPane();
BorderPane mainPane = new BorderPane();
//Create Tabs
Tab tabA = new Tab();
tabA.setText("Main Component");
//Add something in Tab
StackPane tabA_stack = new StackPane();
tabA_stack.setAlignment(Pos.CENTER);
tabA_stack.getChildren().add(new Label("Label#Tab B"));
tabA.setContent(tabA_stack);
tabPane.getTabs().add(tabA);
Tab tabB = new Tab();
tabB.setText("Second Component");
//Add something in Tab
StackPane tabB_stack = new StackPane();
tabB_stack.setAlignment(Pos.CENTER);
tabB_stack.getChildren().add(new Label("Label#Tab B"));
tabB.setContent(tabB_stack);
tabPane.getTabs().add(tabB);
Tab tabC = new Tab();
tabC.setText("Last Component");
//Add something in Tab
StackPane tabC_vBox = new StackPane();
tabC_vBox.setAlignment(Pos.CENTER);
tabC_vBox.getChildren().add(new Label("Label#Tab C"));
tabC.setContent(tabC_vBox);
tabPane.getTabs().add(tabC);
mainPane.setCenter(tabPane);
mainPane.prefHeightProperty().bind(scene.heightProperty());
mainPane.prefWidthProperty().bind(scene.widthProperty());
root.getChildren().add(mainPane);
primaryStage.setScene(scene);
primaryStage.show();
How I can add horizontal and vertical scroll Pane into the tab's body. I want to display the scroll pane only when the data is bigger than the visible area. Is this possible?
Instead of setting contents of tabs to StackPane, call setContent method with ScrollPane object, and set the content of this ScrollPane to the corresponding StackPane.
Creating a basic javafx.scene.control.ScrollPane is easy, an example can be found in the JavaDoc. Here's the code that places a ScrollPane in your first Tab:
...
final Rectangle rect = new Rectangle(200, 200, 800, 600);
rect.setFill(Color.RED);
final ScrollPane scrollPane = new ScrollPane();
scrollPane.setContent(rect);
tabA.setContent(scrollPane);
tabPane.getTabs().add(tabA);
...
You can find a lot of useful examples in the JavaFX tutorials, too.
I want to create JavaFX example similar to this dialog:
I created this code:
public void aboutDialogPanel()
{
final Stage aboutDialog = new Stage();
aboutDialog.initModality(Modality.WINDOW_MODAL);
HBox phbox = new HBox();
phbox.setAlignment(Pos.CENTER);
// Image
ImageView iv = new ImageView(getClass().getResource("/images/splash.png").toExternalForm());
phbox.getChildren().add(iv);
HBox hbox = new HBox();
// Text Area
TextArea dataPane = new TextArea();
dataPane.setEditable(false);
dataPane.setLayoutX(160);
dataPane.setLayoutY(160);
hbox.setAlignment(Pos.CENTER);
hbox.setSpacing(1);
hbox.setPadding(new Insets(10, 0, 10, 0));
hbox.getChildren().add(dataPane);
HBox bhbox = new HBox();
// Close Button
Button closeButton = new Button("Close");
closeButton.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent arg0)
{
// Close the dialog when "Close" button is pressed
aboutDialog.close();
}
});
bhbox.setAlignment(Pos.CENTER);
bhbox.setSpacing(10);
bhbox.setPadding(new Insets(10, 10, 10, 10));
bhbox.getChildren().add(closeButton);
BorderPane borderpane = new BorderPane();
borderpane.setTop(phbox);
borderpane.setCenter(hbox);
borderpane.setBottom(bhbox);
// Configure dialog size and background color
Scene aboutDialogScene = new Scene(borderpane, 600, 500, Color.WHITE);
aboutDialog.setScene(aboutDialogScene);
aboutDialog.show();
}
But I cannot reproduce the same alignment similar to to the picture. Can you tell me how I can fix the layout of my code?
UPDATE
This is the visual result:
The text field is always restricted on left and right.
Add the line
dataPane.prefWidthProperty().bind(hbox.widthProperty());