We have created an internal tool in Java -> Jar. It is created in JavaFX.
The .jar works fine in 9 out of 11 person's computers, but in 2 of them the .jar is in different size. Those 2 people have the window cut smaller for some reason. I will attach the images to show the difference as well.
First, the .jar in working PC (you can clearly see the edges of the .jar and all the fields are clearly visible:
Second, the .jar that is broken (I have painted the areas where you can see that the fields/window is being cut, it's just that the things that are in the frame don't fit there for some reason):
I can provide additional information if required. But currently it just seems that for those 2 computers the fields don't fit in the frame, can it be the difference in java versions or OS?
Edit:
Adding some information about the layouts etc (all the elements are in the grids):
#Override
public void start(final Stage stage) throws Exception {
final Group root = new Group();
GridPane grid0 = new GridPane();
final Scene scene = new Scene(root, 1030, 768);
final GridPane grid = new GridPane();
grid.setHgap(5); //The gap properties manage the spacing between the rows and columns.
grid.setVgap(5); //Vahe iga rea ja veeru vahel pmst.
grid.setPadding(new Insets(40, 20, 20, 20)); //while the padding property manages the space around the edges of the grid pane. Ehk kogu raami sisu vahe ��rtest.
//In this example, there are 10 pixels of padding on each side.
//grid.setGridLinesVisible(true); //N�itab t�pselt joonduse �ra
GridPane grid2 = new GridPane();
grid2.setHgap(5); //The gap properties manage the spacing between the rows and columns.
grid2.setVgap(5); //Vahe iga rea ja veeru vahel pmst.
grid2.setPadding(new Insets(40, 20, 20, 20)); //while the padding property manages the space around the edges of the grid pane. Ehk kogu raami sisu vahe ��rtest.
final GridPane grid3 = new GridPane();
grid3.setHgap(5); //The gap properties manage the spacing between the rows and columns.
grid3.setVgap(5); //Vahe iga rea ja veeru vahel pmst.
grid3.setPadding(new Insets(40, 20, 20, 20)); //while the padding property manages the space around the edges of the grid pane. Ehk kogu raami sisu vahe ��rtest.**strong text**
grid0.add(grid, 0, 0);
Line joon2 = new Line(0, 0, 0, 800);
grid0.add(joon2, 1, 0);
grid0.add(grid2, 2, 0);
final Line joon3 = new Line(0, 0, 0, 800);
grid0.add(joon3, 3, 0);
grid0.add(grid3, 4, 0);
root.getChildren().
add(grid0);
root.getChildren().
add(menuBar);
stage.setResizable(false); //Cannot resize the Bit!
stage.setScene(scene);
stage.show();
Thank you all for the responses, I managed to figure out the problem!
There were 2 options to fix this:
To change windows scaling under "Screen resolution".
I removed the hard-coded scene size and let the size be calculated by the size of the elements in the grids, so it would be dynamic for every computer.
Related
I want to make a form with three sections, two with fields and one with buttons.
public class Form extends Application{
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
StackPane root = new StackPane();
GridPane fp = new GridPane();
fp.setAlignment(Pos.TOP_CENTER);
fp.setHgap(6);
fp.setVgap(6);
fp.add(new Label("Name: "), 0, 0);
TextField name = new TextField();
name.setPrefWidth(450);
fp.add(name, 1, 0);
GridPane sp = new GridPane();
sp.setAlignment(Pos.CENTER);
sp.setHgap(6);
sp.setVgap(6);
sp.add(new Label("Another Name: "), 1, 0);
TextField anothername = new TextField();
anothername.setPrefWidth(120);
sp.add(anothername, 2, 0);
HBox hbox = new HBox();
hbox.setAlignment(Pos.BOTTOM_CENTER);
Button btn1 = new Button("Button 1");
hbox.getChildren().add(btn1);
Scene scene = new Scene(root, 500, 500);
root.getChildren().addAll(fp, sp, hbox);
stage.setScene(scene);
stage.show();
}
}
formatting and some text might be off but that is my general solution. I made a root stack pane to hold all the parts of my form. I then made two grid panes to hold text fields and an hbox to hold my buttons along the bottom.
example of how it looks
My problem is that only the name field can be clicked. If I try to click another name field it wont work. I can press tab to cycle through the fields and button but I want to be able to click on each field individually. Is there a better way to create one scene with multiple panes or hboxes? I am also open to only having one grid pane, but I thought having two would be easier for formatting since I want to separate different fields. Thank you!
The issue you're facing is caused by your using a StackPane as the root element of your scene.
A StackPane, as the name suggests, stacks its children one on top of the other. Any children placed on top will be the ones receiving events (such as clicking on the anothername field).
You have added 3 nodes as children of your StackPane:
GridPane #1 fp
GridPane #2 sp
HBox hbox
Since the HBox was added last, it is the only node that can receive click events.
Using your example, I've added borders to each of the 3 items above to illustrate how JavaFX is laying them out:
As you can see, each child of the StackPane get resized to fill the entire area (I used different widths for the borders so you can see them all).
You can try this yourself by adding the following code before you show your stage:
fp.setStyle("-fx-border-color: green; -fx-border-width: 15px");
sp.setStyle("-fx-border-color: blue; -fx-border-width: 10px");
hbox.setStyle("-fx-border-color: red; -fx-border-width: 5px");
To solve this, you will need to rethink your layout entirely; a StackPane is certainly not the correct layout pane to use in your case.
I highly recommend working through the examples in Oracle's Working With Layouts in JavaFX tutorial to get a better grasp on how to best layout your scene.
The problem I'm having is adding a button to the scene and still maintain the original color of the scene. I have created the scene originally black but when adding the button it becomes white. Do any of you know how to fix this issue?
#Override
public void start(Stage teater) {
teater.setTitle("Adventure Game");
Circle circle = new Circle(200, 100, 30);
circle.setFill(Color.WHITE);
Text text = new Text(Integer.toString(resultat));
text.setFont(Font.font("Calibri", 25));
text.setFill(Color.BLACK);
StackPane root = new StackPane(circle, text);
root.setLayoutX(165);
root.setLayoutY(90);
Text text1 = new Text(50, 40, "Adventure Game");
text1.setFont(Font.font("Edwardian Script ITC", 50));
text1.setFill(Color.WHITE);
Button button = new Button("Avslutt");
button.setTextFill(Color.WHITE);
button.setLayoutX(10);
VBox vBox = new VBox(text1, root);
Pane pane = new Pane(vBox);
pane.setLayoutX(50);
pane.setLayoutY(0);
Scene scene = new Scene(pane, 400, 200, Color.BLACK);
Without button:
With button:
It's not the scene that is changing its background color, but the root of the scene, which is having the styles defined in the default modena.css style sheet applied.
Note that CSS is not applied unless an instance of Control (or one of its subclasses, like Button) is created: the idea here is that styles are mainly defined only for controls, so it's not worth the performance hit for applications that use no controls (purely graphical applications, etc). There is no need to even add the control to the scene graph: as soon as Control's constructor is called, the stylesheet will be applied.
A quick fix is
pane.setStyle("-fx-background-color: transparent ;");
or
pane.setStyle("-fx-background-color: black ;");
but it's probably better to define an external stylesheet:
.root {
-fx-background: black ;
}
as you'll likely find there are other styles you want to control (in fact, with a little work, you can move all the font and color definitions to the CSS file giving your code better separation).
I want to have an HBox container with 3 buttons that are even in width, but when the parent's width can't be divided into whole number parts one of the nodes is less. If my HBox is 245px and I have 3 buttons 1 of them is 81px and the others are 82px.
The problem is that on top of the HBox I have a loading circle indicator and the circle is in the center of the HBox and when the middle button is not centered the loading circle also looks uncentered on top of the HBox.
HBox root = new HBox();
root.setFillHeight(true);
for (int i = 0; i < 3; i++) {
AnchorPane pane = new AnchorPane();
HBox.setHgrow(pane, Priority.ALWAYS);
pane.setMaxHeight(Double.MAX_VALUE);
root.getChildren().add(pane);
}
Scene scene = new Scene(root, 245, 50, Color.TRANSPARENT);
primaryStage.setScene(scene);
primaryStage.initStyle(StageStyle.TRANSPARENT);
primaryStage.show();
root.getChildren().forEach(node -> {
AnchorPane pane = ((AnchorPane)node);
System.out.println(pane.getWidth());
});
The idea is that its a login scene and after submiting the username and password, the server is loading and there is a circle ProgressIndicator on top of the hbox and the circle is centered on top of it.
The circle looks uncentered on top of the middle button. So how can I do this with a layout container without explicity setting the width of the buttons. Do layouts always devide children on whole numbers?
So after some property testing I found out that snapToPixel=false is the way to go.
From oracle docs about snapToPixel https://docs.oracle.com/javase/8/javafx/api/javafx/scene/layout/Region.html
Defines whether this region adjusts position, spacing, and size values of its children to pixel boundaries. This defaults to true, which is generally the expected behavior in order to have crisp user interfaces. A value of false will allow for fractional alignment, which may lead to "fuzzy" looking borders.
I tried different px and in my case it works fine with the edges.
Also without touching the snapToPixel I found that GridPane with 33.3% columns width palces the 81px button in the middle, where with hbox it's the last child, so GridPane also worked for me.
I am trying to make a basic login screen in javafx using the GridPane layout. The issue is that all the labels I put onto the grid are going to position (0,0) seemingly ignoring my values for the column and row indices.
I've tried putting extreme values for the indices into both function calls and nothing moves. It seems to ignore any indices I give it and defaults to (0,0).
GridPane setup:
GridPane grid = new GridPane();
grid.setPadding(new Insets(10, 10, 10, 10));
grid.setVgap(10);
grid.setHgap(10);
The function calls for the Labels:
// Name label
Label nameLabel = new Label("Username:");
GridPane.setConstraints(grid, 0, 0);
// Password label
Label passLabel = new Label("Password:");
GridPane.setConstraints(grid, 0, 1);
Adding GridPane to scene:
grid.getChildren().addAll(nameLabel, nameInput, passLabel, passInput, loginButton);
Scene scene = new Scene(grid, 300, 200);
You are using GridPane.setConstraints(); incorrectly. Instead of setting the constraints on grid, you should be setting the constraints on the nodes. Examples:
// Name label
Label nameLabel = new Label("Username:");
GridPane.setConstraints(nameLabel, 0, 0);
// Password label
Label passLabel = new Label("Password:");
GridPane.setConstraints(passLabel, 0, 1);
See javadocs for more details.
I have a project that has a 2 text areas and few buttons. The root pane is a AnchorPane. when resizing the window to smaller window, all the elements start overlap. What methods can fix this? (IGNORE THE NAME OF MY anchorpane, i got lazy)
AnchorPane borderpane = new AnchorPane ();
TextArea user_list = new TextArea();
user_list.setPrefSize(150, 400);
TextArea messages = new TextArea();
messages.setPrefSize(350, 400);
TextField typebox = new TextField();
typebox.setPrefSize(425, 100);
// put a shape over a text, over a shape
StackPane send_container = new StackPane();
Rectangle send_box = new Rectangle(75, 25);
Label send_text = new Label("Send");
send_container.getChildren().add(send_box);
send_container.getChildren().add(send_text);
AnchorPane.setLeftAnchor(messages, 25.0);
AnchorPane.setTopAnchor(messages, 10.0);
AnchorPane.setRightAnchor(user_list, 25.0);
AnchorPane.setTopAnchor(user_list, 10.0);
AnchorPane.setBottomAnchor(typebox, 25.0);
AnchorPane.setLeftAnchor(typebox, 25.0);
AnchorPane.setBottomAnchor(send_container, 25.0);
AnchorPane.setRightAnchor(send_container, 25.0);
borderpane.getChildren().addAll(messages, user_list, typebox,send_container );
Scene scene = new Scene(borderpane, 600, 600);
primaryStage.setMaxHeight(600);
primaryStage.setMaxWidth(600);
primaryStage.setScene(scene);
primaryStage.setTitle("Welcome");
scene.getStylesheets().add(LoginWindow.class.getResource("Login.css").toExternalForm());
primaryStage.show();
You are hard-coding the locations and sizes of your controls. This means the controls cannot respond to changes in the size of their parent nodes.
Usually, you should not specify any heights or widths. Controls all have default preferred sizes, and all layouts respect those. Layouts also decide how child nodes will be resized in response to the user's resizing of a window.
Often, the layout of a window needs to be broken down into sub-layouts. In your case, you want one section that always resizes to fill the window (the user list and message section), with another section at the bottom (the typebox and Send button). A BorderPane is the ideal choice, since its center node always fills it. So the center of this main BorderPane would contain the user list and message area, while the bottom of this BorderPane would contain the typebox and the Send button.
You probably want the user to be able to horizontally resize both the user list and the messages, so I'd put them in a SplitPane, and make that SpiltPane the center of the main BorderPane.
You probably want the typebox and Send button to be in a separate child BorderPane, with the typebox as the center node, since you want the typebox to stretch and shrink, horizontally, when the user resizes the window.
So, to summarize:
user list and message area in a SplitPane
typebox and Send button in a BorderPane
parent BorderPane with user list/message section in the center, typebox/Send section on the bottom
The code for this is actually pretty short:
ListView user_list = new ListView();
TextArea messages = new TextArea();
messages.setPrefRowCount(12);
messages.setPrefColumnCount(30);
TextField typebox = new TextField();
typebox.setPrefColumnCount(30);
Button send_text = new Button("Send");
send_text.disableProperty().bind(
typebox.lengthProperty().lessThan(1));
SplitPane top = new SplitPane(user_list, messages);
top.setDividerPosition(0, 1/3.0);
BorderPane bottom = new BorderPane();
bottom.setCenter(typebox);
bottom.setRight(send_text);
BorderPane.setMargin(typebox, new Insets(0, 12, 0, 0));
BorderPane main = new BorderPane();
main.setCenter(top);
main.setBottom(bottom);
BorderPane.setMargin(bottom, new Insets(12));
Scene scene = new Scene(main);
primaryStage.setScene(scene);
primaryStage.setTitle("Welcome");
scene.getStylesheets().add(LoginWindow.class.getResource("Login.css").toExternalForm());
primaryStage.show();
Notice that there are no hard-coded dimensions or coordinates (except the margins defined by the Insets objects). Every control has a preferred size based on its properties, such as a TextField's preferred column count.
The workings of the various layouts are well documented. I suggest reading about them in the javafx.scene.layout package.
(I'm guessing the user list should be a ListView, not a TextArea, since typical chat programs allow selection of one or more users. And I suspect your black Rectangle and send_text Label were intended to represent a disabled Button.)
Use a pane other than a Anchor Pane. It's for absolute positioning. Try a stack pane or simple VBox.