Scene color becomes white when adding button - java

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

Related

How do I make all the fields in my javafx form clickable using GridPane and HBox?

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.

Setting the alignment of a node without using BorderPane?

So I have a Text node which I want to position at the Top-Right side of the scene. Most methods state to use BorderPane, but in my case some of the other nodes in my scene are using Panewhich is also my root pane, so the obvious workaround is to add the nodes you want to the BorderPane and add the BorderPane to the root Pane.
However BorderPane does not seem to be compatible with the Pane. That is, all the nodes of the BorderPane won't be shown. Also positioning the nodes based on their translate X and Y are not supported in BorderPane as well.(i.e. setLayoutX() does not work.) Because of this I cannot even make my root Pane to BorderPane.
Here is what I've tried:
public class foo {
private Pane root = new Pane();
private BorderPane borderPane = new BorderPane();
private Scene scene = new Scene(root, 1366, 768);
public foo(){
Text text1 = new Text("test1");
text1.setLayoutX(11); // Ignore this if you want.
test1.setLayoutY(11);
Text text2 = new Text("test2");
root.getChildren().add(test1);
borderPane.setRight(text2);
root.getChildren().add(borderPane);
// Display the scene on a stage.
}
}
Here only test1 is shown and test2 is not seen.
Is there a way I can position this text on the RIGHT TOP side of the screen without using BorderPane?
Pane just resizes the children to the preferred size. Since you only place the Text node as child of the BorderPane, its preferred size is the size of the child.
In this case I recommend using a different layout, e.g.
StackPane
This allows you set the alignment of a node within the layout using StackPane.setAlignment(child, newAlignment);. The drawback is that setting an absolute position requires you to either make the child unmanaged (with some side effects) or specifying 4 values (an Insets instance) as margin.
Text text1 = new Text("test1");
StackPane.setMargin(text1, new Insets(11, 0, 0, 11));
StackPane.setAlignment(text1, Pos.TOP_LEFT);
Text text2 = new Text("test2");
StackPane.setAlignment(text2, Pos.TOP_RIGHT);
root = new StackPane(text1, text2);
AnchorPane
This does not allow for center alignments, but it allows you to set absolute positions using layoutX and layoutY just the way you'd do in a Pane. You can set anchor properties to specify the distance of a child from the top, left, right and/or bottom:
Text text1 = new Text("test1");
text1.setLayoutX(11);
text1.setLayoutY(11);
Text text2 = new Text("test2");
AnchorPane.setRightAnchor(text2, 0d);
AnchorPane.setTopAnchor(text2, 0d);
root = new AnchorPane(text1, text2);

How to make a TextField fill all the remaining width of a pane containing multiple nodes?

I need to make a chat-simulating JavaFX application for my assignment (no web functionalities, just two text fields for input and two text areas for output). I need to have a “Send” button next to my text field. I cannot make the text field to fill up the width of my window without “squishing” the button at startup, similarly to how swing’s boxLayout does that?
I bound the field’s width to the parent pane’s width, subtracting the button’s width and the pane’sspacing and it works after I start resizing the window, but when the application first starts up, the button’s text is not fully visible.
public void start(Stage stage_main) throws Exception {
//Pane creation and nesting:
HBox pane_main = new HBox();
Scene scene_main = new Scene(pane_main, 480, 360);
BorderPane pane_left_parent = new BorderPane();
BorderPane pane_right_parent = new BorderPane();
HBox pane_left_bottom = new HBox();
HBox pane_right_bottom = new HBox();
pane_main.getChildren().addAll(pane_left_parent, pane_right_parent); //Focusing only on the left pane for now for testing.
pane_left_parent.setBottom(pane_left_bottom);
//Contents creation and nesting:
TextArea textA_left = new TextArea("Testing...");
Button button_left = new Button("Send");
TextField textF_left = new TextField("Test input...");
textF_left.prefWidthProperty().bind(pane_left_bottom.widthProperty().subtract(button_left.widthProperty()).subtract(pane_left_bottom.spacingProperty()));
//Placing contents in panes:
pane_left_parent.setCenter(textA_left);
pane_left_bottom.setSpacing(3);
pane_left_bottom.getChildren().addAll(textF_left, button_left);
//Finishing up:
stage_main.setScene(scene_main);
stage_main.show();
}
Is there any way to have the button have it’s “best” size already at startup without manually setting any widths in pixels, just like in swing?
Don't bind the prefWidth to the parent. If you want a child of an HBox to grow horizontally you can set an hgrow constraint on it:
HBox.setHgrow(theChild, Priority.ALWAYS);
Then let the HBox handle sizing and positioning the child node. And as you noted, in order to stop the Button from shrinking as the HBox changes size you need to set its minWidth. However, you should use:
button.setMinWidth(Region.USE_PREF_SIZE);
If you use getWidth() you might accidentally call it before the Button actually has a non-zero width. Plus, using USE_PREF_SIZE means the minWidth will stay up-to-date with the prefWidth (if you change it for whatever reason).
Some links:
HBox#.setHgrow(Node,Priority)
Priority
Region#USE_PREF_SIZE

Problem between scene background a a new Label in JavaFX

I'm approaching to develope a Snake Game with JavaFX (I'm benniger).
In the main method I have set scene.setFill(Color.BLACK) and so the background is totally black. When I add a Label, when I try to instantiate it, the background disappear and the Label is not shown on the screen.
It does not happen if I add Rectangle or Circle, but only with Labels, Buttons ecc.
How can I do to solve this? I think it is a simple question but I can not solve it by myself.
/Main.java
GamePanel g = new GamePanel();
BorderPane root = new BorderPane();
//Scene scene = new Scene(root,400,400, Color.BLACK);
Scene scene = new Scene(root,400,400);
scene.setFill(Color.BLACK);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.setTitle("SnakeFX");
primaryStage.show();
root.getChildren().add(g);
g.requestFocus();
/GamePanel.java (I put only a part of the function initialize() that
is the first function of the constructor and that initialize the
gamegraphics and that must contain my label)
void initialize() {
/* IF I PUT THIS LINE THE BLACK COLOR ON THE BACKGROUND DISAPPEAR
AND LABEL DOES NOT APPEAR ON THE SCREEN.
WITHOUT THIS LINE THE GAME RUNS PERFECTLY B BUT I NEED THIS LINE TO ADD
THE SCORE EHEH */
Label l = new Label("TEST"); //this is the line
for(int i=0;i<WIDTH;i=i+WIDTH/40) {
Line line = new Line();
line.setStartX((double)i);
line.setStartY(0.0);
line.setEndX((double)i);
line.setEndY((double)HEIGHT);
line.setVisible(true);
super.getChildren().add(line);
}
for(int j=0;j<HEIGHT;j=j+HEIGHT/40) {
Line line = new Line();
line.setStartY((double)j);
line.setStartX(0.0);
line.setEndY((double)j);
line.setEndX((double)WIDTH);
line.setVisible(true);
super.getChildren().add(line);
}
....
...
. ..
}
First image is without the instantiation of the label.
Second image is with the instantiation of the label (The background color is not shown and the label is not shown)
This is a JavaFx bug (see this answer).
What you see in your second image is the root node's (BorderPane) background color (which is defined in javafx default theme and it's not transparent). This is the correct state - the first image shows the bug described in the answer linked above.
You can fix your problem easily:
remove the background color from the root node, so the scene's background color becomes visible:
root.setBackground(Background.EMPTY);
or, set the root node's background color to black:
root.setBackground(new Background(new BackgroundFill(Color.BLACK, null, null)));

JavaFX 8: How to be able to re-size window (stage) but keep inner elements at their positions?

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.

Categories

Resources