public void start(Stage primaryStage) {
primaryStage.setTitle("Hello World!");
ScrollBar sc = new ScrollBar();
sc.setMin(0);
sc.setMax(100);
Button btn = new Button();
btn.relocate(150, 100);
btn.setText("Launch Keyboard lights");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Hello World!");
}
});
StackPane root = new StackPane();
root.getChildren().add(btn);
root.getChildren().add(sc);
primaryStage.setScene(new Scene(root, 300, 250));
primaryStage.show();
}
I tried using btn.setXlayout and y and it also didn't work. I think its because of the root of (new Scene(root, 200, 250)); but what am I supposed to write to get the button into a new position?
A StackPane is probably not what you want here - it is used to stack controls on top of one another (z-axis), but the controls themselves are positioned according to the Alignment property of the StackPane.
You are probably looking for something like AnchorPane, which allows you to anchor controls to one or more sides of the pane. Alternatively, you can use one of the many other layout panes available in JavaFX, depending on what layout you are looking to achieve.
Take a look at this tutorial to get an idea of the various layout panes available. Also, you may want to play around with Scene Builder at least for prototyping.
A StackPane is a layout pane, which means it organizes the layout of its child nodes for you. (By default it centers them, though you can change that so that it positions them in any of the alignments specified by Pos.)
The recommendation is that you use a layout pane, or combination of layout panes, that manage the child nodes in the way you want. If you really want to position them yourself (really, you don't), you can use a Pane as the root instead of a StackPane, and then use btn.setLayoutX and btn.setLayoutY(...)
Try this
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.deneme
import javafx.scene.control.ScrollBar;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class MainApp extends Application {
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Hello World!");
ScrollBar sc = new ScrollBar();
sc.setMin(0);
sc.setMax(100);
Pane pane = new Pane();
Button btn = new Button();
pane.setPrefSize(300,250);
btn.setText("Launch Keyboard lights");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("asda");
}
});
StackPane root = new StackPane();
pane.getChildren().add(btn);
pane.getChildren().add(sc);
btn.setLayoutX(50); //this is how you change locations
btn.setLayoutY(50); //this is how you change locations
root.getChildren().add(pane);
primaryStage.setScene(new Scene(root, 300, 250));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Related
I am currently coding a board game and I am using java and for GUI purposes javaFX. The game requires for a map (the game board) to be in the middle of the screen and various options and additional information to be around it. My idea was to have a BorderPane where the center node is the game board and top, bottom etc are the additional options.
My problem is that upon starting the App the BorderPane is not centered in the stage but is slightly extended to the right and botton, where it is not visible. Thus my bottom Node can't be seen. Strangely if I minimize the window and maximize it again everything is where it should be and perfectly inside the bounds of the stage.
The application before minimizing and maximizing again
And afterwards (The way it should look like from the beginning)
My center Node is a normal Pane. Also I do stage.setMaximize(true). So the window is already maximized upon starting the application and it should not make a difference to minimze and maximize again.
The code for this scene essentially boils down to this:
#Override
public void start(Stage stage) throws Exception {
this.stage = stage;
Pane pane = createGameBoard();
pane.setId("mapPane");
Button button = new Button("Save");
VBox box = new VBox(0, button);
box.setAlignment(Pos.CENTER);
Label label = new Label("Bottom");
label.setPrefHeight(20);
BorderPane borderPane = new BorderPane();
borderPane.setTop(top);
borderPane.setBottom(bottom);
borderPane.setCenter(center);
borderPane.setPadding(new Insets(10));
Scene scene = new Scene(borderPane);
scene.getStylesheets().add(Objects.requireNonNull(MainGUI.class.getResource("/game.css")).toString());
stage.setScene(scene);
}
The game.css stylesheet only sets a background colour at the moment.
I am using: Java 17, JavaFX 17.
If you need any further information I am happy to provide it :)
Thanks!
Edit:
To reproduce my problem run this code. The issue should appear once you click on the button "Next Screen".
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class App extends Application {
private Stage stage;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
this.stage = stage;
stage.setTitle("App");
stage.setMinHeight(600);
stage.setMinWidth(800);
stage.setWidth(java.awt.Toolkit.getDefaultToolkit().getScreenSize().getWidth());
stage.setHeight(java.awt.Toolkit.getDefaultToolkit().getScreenSize().getHeight());
stage.setMaximized(true);
stage.setOnCloseRequest(e -> System.exit(0));
Button button = new Button("Next Screen");
button.setOnAction(e -> {gameScreen();});
BorderPane borderPane = new BorderPane();
borderPane.setCenter(button);
Scene scene = new Scene(borderPane);
stage.setScene(scene);
stage.show();
}
private void gameScreen() {
Circle circle = new Circle(0, 0, 4);
Pane pane = new Pane(circle);
pane.setStyle("-fx-background-color: #00c3ff");
Button button = new Button("Top");
VBox vBox = new VBox(0, button);
vBox.setAlignment(Pos.CENTER);
Label label = new Label("Bottom");
BorderPane borderPane = new BorderPane();
borderPane.setTop(vBox);
borderPane.setCenter(pane);
borderPane.setBottom(label);
borderPane.setPadding(new Insets(10));
Scene scene = new Scene(borderPane);
stage.setScene(scene);
}
}
My problem was resolved by changing the root of the scene I was using and not create a new scene everytime I switch the layout (e.g. from main menu to the game screen).
How to make text in TextFlow justify left, but the TextFlow is in the center of the window?
I try to implement it with VBox, StackPane and BorderPane, but they can only align the text in the center, or make the TextFlow to the left of the window.
The effect I need is similar to IDEA:
But the effect I achieved is like this:
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
TextFlow text = new TextFlow(
new Text("Search Everywhere\n"),
new Text("Project View\n"),
new Text("Go to File\n")
);
text.setTextAlignment(TextAlignment.LEFT);
VBox root = new VBox(text);
root.setAlignment(Pos.CENTER);
primaryStage.setScene(new Scene(root, 400, 400));
primaryStage.show();
}
}
Thanks for c0der tips, I found FlowPane can easily achieve this effect:
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
TextFlow text = new TextFlow(
new Text("Search Everywhere\n"),
new Text("Project View\n"),
new Text("Go to File\n")
);
text.setTextAlignment(TextAlignment.LEFT);
FlowPane root = new FlowPane(text);
root.setAlignment(Pos.CENTER);
primaryStage.setScene(new Scene(root, 400, 400));
primaryStage.show();
}
}
I am not sure this is exactly what you are looking for, but should put you in the right direction. I added color so you can see where one control ends and the other continues.
To make this work you need to ensure that your TextFlow doesn't size bigger than what you want, otherwise it will not give you the expected behavior. In this instance I choose 200x200 and you will see it center in the window.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.text.Text;
import javafx.scene.text.TextAlignment;
import javafx.scene.text.TextFlow;
import javafx.stage.Stage;
public class Sample extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
TextFlow tf = new TextFlow();
tf.setStyle("-fx-background-color: red;");
tf.setTextAlignment(TextAlignment.LEFT);
tf.setMaxSize(200, 200);
StackPane sp = new StackPane(tf);
sp.setStyle("-fx-background-color: blue;");
Text t1 = new Text("This is line one, left justified" + System.lineSeparator());
Text t2 = new Text("This is line two, left justified"+ System.lineSeparator());
Text t3 = new Text("This is line three, left justified"+ System.lineSeparator());
Text t4 = new Text("This is line four, left justified"+ System.lineSeparator());
tf.getChildren().addAll(t1, t2, t3, t4);
Scene scene = new Scene(sp);
primaryStage.setScene(scene);
primaryStage.setWidth(600);
primaryStage.setHeight(600);
primaryStage.show();
}
}
If I open another JavaFX (modal) Stage, and set its owner as the original Stage, then the original Stage can't be resized, using the windows drag widget on the bottom right hand corner of the window
I see this in Linux but don't own windows or MacOS so can't test it elsewhere...
here is a minimal example
import javafx.stage.*;
import javafx.scene.*;
import javafx.event.*;
import javafx.application.*;
import javafx.scene.layout.*;
import javafx.scene.control.*;
public class HelloWorld extends Application
{
static Stage newStage;
#Override
public void start(Stage primaryStage)
{
Button btn = new Button();
btn.setText("open window");
btn.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent event)
{
if (newStage==null)
{
Button newBtn = new Button("Close window");
newBtn.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent event)
{
//newStage.hide(); // either or
newStage.close();
}
});
newStage = new Stage();
newStage.initModality(Modality.WINDOW_MODAL);
newStage.initOwner(primaryStage); // BUG doing this, makes main window fixed size
newStage.initStyle(StageStyle.DECORATED);
StackPane newRoot = new StackPane();
newRoot.getChildren().add(newBtn);
Scene newScene = new Scene(newRoot,200,160);
newStage.setScene(newScene);
}
newStage.show();
}
});
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args)
{
launch(args);
}
}
This is a confirmed Java bug. Looks like it's targeted for fixing in Java 10 sometime.
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8140491
That said, I'd love a workaround if someone has one.
Edit: one workaround I've found, ugly as it is, is that you can hide and show the owner stage after hiding the modal child stage. That re-enables resizing. You see the stage disappear and reappear, though, which is messy.
package example;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
Text text = new Text("This is a Text");
VBox box = new VBox();
box.setAlignment(Pos.CENTER);
box.setStyle("-fx-background-color: yellow;");
box.getChildren().add(text);
StackPane container = new StackPane();
container.getChildren().add(box);
BorderPane bp = new BorderPane();
bp.setCenter(container);
Scene scene = new Scene(bp, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Here's the output:
Question: Can someone explain to me why the Vbox fill the whole screen? Is there a method that is similar to Android's wrap_content? I want the image below to be the output:
Solution
Wrap the VBox in a Group; e.g. use:
container.getChildren().add(new Group(box));
instead of:
container.getChildren().add(box);
Why it works
From the Group javadoc:
By default, a Group will "auto-size" its managed resizable children to their preferred sizes during the layout pass.
This means that the VBox won't grow past the preferred size of it's content (which is just enough area to display the label inside it).
Alternate implementation
Set the maximum size of the VBox to the preferred size. Then the VBox will only ever grow large enough to fit the preferred size of the content inside it and will never grow any larger.
box.setMaxSize(VBox.USE_PREF_SIZE, VBox.USE_PREF_SIZE);
Why VBox grows by default
It is a resizable container which will stretch to fill available area.
Note
I don't know that the effect is exactly the same as an Android wrap_content method as I have never developed for Android, however the effect does seem to exactly match the second image you provided in your question, which appears to be what you want.
VBox automatically resizes itself to the size of the Parent, so it is better not to set background color to it. Instead, you can use a Label in place of a Text and then add background color to the Label instead of the VBox.
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
Label text = new Label("This is a Text");
VBox box = new VBox();
box.setAlignment(Pos.CENTER);
text.setStyle("-fx-background-color: yellow;");
box.getChildren().add(text);
StackPane container = new StackPane();
container.getChildren().add(box);
BorderPane bp = new BorderPane();
bp.setCenter(container);
Scene scene = new Scene(bp, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
This will give you an output like an image below:
I'm extremely new to JavaFX, and I'm attempting to get a button(specifically scrapeBtn) into the bottom right corner of an application. Here is what I have so far:
package main;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Driver extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
Button scrapeBtn = new Button();
scrapeBtn.setText("Scrape!");
scrapeBtn.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
System.out.println("Scrape button pressed.");
}
});
TextField console = new TextField();
GridPane root = new GridPane();
GridPane.setConstraints(scrapeBtn, 2, 2, 1, 1);
root.getChildren().add(scrapeBtn);
root.getChildren().add(console);
Scene scene = new Scene(root, 600, 400);
primaryStage.setTitle("Wiki Scraper");
primaryStage.setScene(scene);
primaryStage.show();
}
}
Any ideas as to how I could accomplish this? Some tips in general to aligning and formatting things with JavaFX would also be really appreciated.
Thanks.
I often use a BorderPane for similar purposes (e.g. a Dialog with some text and controls etc. at the center and one or more buttons at the bottom). Therefore, I use the BorderPane as root and a HBox as "button container" at the bottom. Finally, I set the botton alignment to "RIGHT".
Here an example based on your code:
#Override
public void start(Stage primaryStage) {
// center
VBox vbCenter = new VBox(); // use any container as center pane e.g. VBox
TextField console = new TextField();
vbCenter.getChildren().add(console);
// bottom respectively "button area"
HBox hbButtons = new HBox();
Button scrapeBtn = new Button();
scrapeBtn.setText("Scrape!");
scrapeBtn.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
System.out.println("Scrape button pressed.");
}
});
hbButtons.getChildren().add(scrapeBtn);
hbButtons.setAlignment(Pos.CENTER_RIGHT);
// root
BorderPane root = new BorderPane();
root.setPadding(new Insets(20)); // space between elements and window border
root.setCenter(vbCenter);
root.setBottom(hbButtons);
Scene scene = new Scene(root, 600, 400);
primaryStage.setTitle("Wiki Scraper");
primaryStage.setScene(scene);
primaryStage.show();
}
This code leads to this (after resizing the window a little bit):
You can use two BorderPanes to place a control bottom right
#Override
public void start(Stage primaryStage) throws Exception {
BorderPane root = new BorderPane();
BorderPane bottom = new BorderPane();
bottom.setRight(new Button("I am placed bottom right"));
root.setBottom(bottom);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.setWidth(400);
primaryStage.setHeight(400);
primaryStage.show();
}