JavaFX not showing full web page on 16:9 ratio - java

Heres the code:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
public class Main extends Application{
public static void main(String[] args){
Application.launch(args);
}
#Override
public void start(Stage stage) throws Exception{
WebView myWebView = new WebView();
WebEngine engine = myWebView.getEngine();
engine.load("https://twitter.com/");
VBox root = new VBox();
root.getChildren().addAll(myWebView);
Scene scene = new Scene(root, 1280, 720);
stage.setScene(scene);
stage.show();
}
}
If I run this it will show the web page on the top 3 quarters of the application window with a white box taking up the other quarter. It's even worse if I maximise the window, the site only takes up about half of the application window. Not sure whats causing this...

You will need to make it fill the entire space on the Stage. Depending on your choice you will have the above cases.
Case 1 : Using a BorderPane.
By adding the BorderPane directly to the Stage and the WebView on the center of the BorderPane it will make the webView take all the available width and height of the Stage.
Example :
#Override
public void start(Stage stage) throws Exception {
WebView myWebView = new WebView();
WebEngine engine = myWebView.getEngine();
engine.load("https://twitter.com/");
BorderPane root = new BorderPane();
root.setCenter(myWebView);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
Case 2 : Using a VBox or HBox.
Those panes takes by default all the available width for VBox and height for HBox space and left the other dimension to be calculated by their children nodes. In order to utilize the full space you need to tell the node inside those panes to always grow ( vertical or horizontal depending of the pane )
Example :
#Override
public void start(Stage stage) throws Exception {
WebView myWebView = new WebView();
WebEngine engine = myWebView.getEngine();
engine.load("https://twitter.com/");
VBox root = new VBox(); // or HBox
root.getChildren().add(myWebView);
// HBox.setHgrow(myWebView, Priority.ALWAYS);
VBox.setVgrow(myWebView, Priority.ALWAYS);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
There are a lot of other panes as well like AnchorPane ( which you will need to set its anchors ) or FlowPane etc and in some cases you will have to bind their prefWidthProperty and prefHeightProperty with the actual widthProperty/heightProperty of the Stage. But I believe you got the point.

Related

JavaFX - BorderPane is not centered in scene/stage

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).

primaryStage cannot be resolved to a variable:,When using in other class: JavaFX

I know There are many Questions related to this particular error, But I couldn't Find a solution that fits my Error.
So What I am doing is creating a javaFX Application and using the Modality library so that I can create a subwindow which opens always above of the Primary Stage. But the Error I am getting that I am not able set the primaryStage Variable inside the initOwner() function because of the Scope issue as PrimaryStage is outside the scope of SubModal Class.
let me put some code to make things clear..
//SubModal Class
class SubModal extends singleModal {
SubModal()
{
Stage subStage1 = new Stage();
subStage1.setTitle("New Stage1");
FlowPane root = new FlowPane();
root.setAlignment(Pos.CENTER);
Scene scene1 = new Scene(root, 300, 200);
Button btn2 = new Button("Button: Stage1");
root.getChildren().add(btn2);
btn2.setOnAction(eve-> System.out.println("Clicked on Stage 1 Button"));
subStage1.initOwner(primaryStage);
subStage1.initModality(Modality.NONE);
subStage1.setScene(scene1);
subStage1.show();
}
}
//SingleModal Class
public class singleModal extends Application {
public static void main(String[] args) {
Application.launch(args);
}
public void start(Stage primaryStage) {
primaryStage.setTitle("PrimaryStage");
FlowPane root = new FlowPane();
root.setAlignment(Pos.CENTER);
Scene scene = new Scene(root, 700, 200);
Button btn = new Button("Open New Stage");
btn.setOnAction(eve-> new NewStage());
root.getChildren().add(btn);
primaryStage.setScene(scene);
primaryStage.show();
}
}
From the above code..
subStage1.initOwner(primaryStage);
This particular line Shows the Error
primaryStage cannot be resolved to a variable
I Know it's because PrimaryStage() is not available in the subModal Class.
So My question is that How Can I fix this issue in JavaFX. How can I bring the primaryStage Value in the SubModal Class so that I can run this Code ErrorFree
For the needed functionality ("create a subwindow which opens always above of the Primary Stage") there is no need to extend singleModal.
Here is an mre demonstrating it:
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.FlowPane;
import javafx.stage.Modality;
import javafx.stage.Stage;
public class SingleModal extends Application {
#Override
public void start(Stage primaryStage) {
Stage subStage1 = new Stage();
subStage1.setTitle("New Stage1");
Button btn2 = new Button("Button: Stage1");
FlowPane root2 = new FlowPane();
root2.setAlignment(Pos.CENTER);
root2.getChildren().add(btn2);
btn2.setOnAction(eve-> System.out.println("Clicked on Stage 1 Button"));
subStage1.initOwner(primaryStage);
subStage1.initModality(Modality.NONE);
Scene scene1 = new Scene(root2, 300, 200);
subStage1.setScene(scene1);
primaryStage.setTitle("PrimaryStage");
FlowPane root = new FlowPane();
root.setAlignment(Pos.CENTER);
Scene scene = new Scene(root, 700, 200);
Button btn = new Button("Open New Stage");
btn.setOnAction(eve-> subStage1.show());
root.getChildren().add(btn);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
I think what u want is just add the code in the start method. I have no idea what the SubModule class is for.
Further Modality is not a library. Maybe call it a feature.
Maybe that example helps http://java-buddy.blogspot.com/2013/08/javafx-example-modality.html .
So add
Stage subStage1 = new Stage();
subStage1.setTitle("New Stage1");
FlowPane root = new FlowPane();
root.setAlignment(Pos.CENTER);
Scene scene1 = new Scene(root, 300, 200);
Button btn2 = new Button("Button: Stage1");
root.getChildren().add(btn2);
btn2.setOnAction(eve-> System.out.println("Clicked on Stage 1 Button"));
subStage1.initOwner(primaryStage);
subStage1.initModality(Modality.NONE);
subStage1.setScene(scene1);
subStage1.show();
to the end of the start method.

How to set the coordinate for my button in JavaFX?

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);
}
}

wrap content in JavaFX

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:

How to align a button into the bottom right corner in JavaFX?

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();
}

Categories

Resources