I am trying to solve an issue with a calculator project I am working on with javafx 11 and java11 using Scene Builder. I am trying to figure out a way to make the buttons on the calculator change color when typing the corresponding value from the keyboard. Is there a method, or onKeyPressed etc type solution to this issue?
I was able to make the button change colors when the a user clicks on it with a mouse (changes to green). This was accomplished in my css style sheet. I tried to add a method to my onKeyReleased method in my controller class, and could change the background that way, but could not determine a way to have the color change back in a timely manner without causing a lag on the UI. I want the UI to change colors similar to most calculators such as the standard windows calculator. This is where a user holds the key down and it changes color, and when releasing the key it changes back.
//main.java
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
Parent root =
FXMLLoader.load(getClass().getResource("calculator.fxml"));
primaryStage.getIcons().add(new Image("CALC.png"));
primaryStage.setTitle(" TS Calculator");
primaryStage.setScene(new Scene(root, 250, 375));
primaryStage.setResizable(true);
primaryStage.setMinHeight(375);
primaryStage.setMinWidth(250);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
/CSS
Button{
-fx-background-color: black;
-fx-text-align: center;
-fx-text-fill: white;
-fx-border-color: green;
-fx-font-size: 1em;
-fx-border-radius: 10 10 10 10;
-fx-background-radius: 10 10 10 10;
}
Button:pressed{
-fx-background-color: green;
}
TextField{
-fx-font-size: 1.5em;
}
//FXML (Only showing 1 button)
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<GridPane maxHeight="1.7976931348623157E308"
maxWidth="1.7976931348623157E308" minHeight="306.00" minWidth="204.0"
prefHeight="288.0" prefWidth="208.0" style="-fx-background-color:
DARKSLATEGREY; -fx-border-color: green;"
stylesheets="#styles.css" xmlns="http://javafx.com/javafx/11.0.1"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="com.trevorsmith.Controller"
onKeyReleased="#acceptKeyboardInput">
<AnchorPane prefHeight="200.0" prefWidth="200.0" GridPane.columnSpan="4"
GridPane.hgrow="ALWAYS" GridPane.vgrow="ALWAYS"
onKeyPressed="#acceptKeyboardInput">
<children>
<TextField fx:id="textFieldDisplay" editable="false"
alignment="CENTER_RIGHT" maxHeight="1.7976931348623157E308"
maxWidth="1.7976931348623157E308" prefWidth="196.0"
AnchorPane.bottomAnchor="2.0" AnchorPane.leftAnchor="2.0"
AnchorPane.rightAnchor="2.0" AnchorPane.topAnchor="2.0" />
</children>
</AnchorPane>
<AnchorPane maxHeight="1.7976931348623157E308"
maxWidth="1.7976931348623157E308" prefHeight="200.0" prefWidth="200.0"
GridPane.hgrow="ALWAYS" GridPane.rowIndex="1" GridPane.vgrow="ALWAYS">
<children>
<Button maxHeight="1.7976931348623157E308"
maxWidth="1.7976931348623157E308" text="0" AnchorPane.bottomAnchor="0.0"
AnchorPane.leftAnchor="2.0" AnchorPane.rightAnchor="0.0"
AnchorPane.topAnchor="0.0" />
</children>
I am unable to make the background color change on click, and when I release my key it change back.
You'll want to register a couple of listeners on your Scene to listen to the pressed keys.
Once you have the key, you can use JavaFX's PseudoClass selectors to update the pressed style of each Button.
There could be a more streamlined way to do this, but this is my implementation. Here is a complete sample you can try out to see it in action.
Note that I did not implement the actual functionality of the calculator.
Final result/screenshot at the end.
Main.java:
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("MainLayout.fxml"));
Scene scene = new Scene(loader.load());
scene.getStylesheets().add("style.css");
primaryStage.setScene(scene);
primaryStage.setTitle("Calculator");
primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
}
MainLayout.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<VBox alignment="TOP_CENTER" spacing="10.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="UI.BaseApps.Calculator.MainController">
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
</padding>
<children>
<TextField fx:id="txtDisplay" disable="true" alignment="CENTER_RIGHT" editable="false" minHeight="-Infinity"
prefHeight="50.0" text="0"/>
<GridPane hgap="10.0" vgap="10.0" VBox.vgrow="ALWAYS">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="-Infinity"/>
<ColumnConstraints hgrow="SOMETIMES" minWidth="-Infinity"/>
<ColumnConstraints hgrow="SOMETIMES" minWidth="-Infinity"/>
<ColumnConstraints hgrow="NEVER" minWidth="-Infinity"/>
<ColumnConstraints hgrow="SOMETIMES" minWidth="-Infinity"/>
<ColumnConstraints hgrow="SOMETIMES" minWidth="-Infinity"/>
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="-Infinity" vgrow="SOMETIMES"/>
<RowConstraints minHeight="-Infinity" vgrow="SOMETIMES"/>
<RowConstraints minHeight="-Infinity" vgrow="SOMETIMES"/>
<RowConstraints minHeight="-Infinity" vgrow="SOMETIMES"/>
</rowConstraints>
<children>
<Button fx:id="btn7" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="7"/>
<Button fx:id="btn8" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="8" GridPane.columnIndex="1"/>
<Button fx:id="btn9" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="9" GridPane.columnIndex="2"/>
<Separator orientation="VERTICAL" prefHeight="200.0" GridPane.columnIndex="3" GridPane.rowSpan="4"/>
<Button fx:id="btnDivide" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="÷" GridPane.columnIndex="4"/>
<Button fx:id="btnClear" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="C" GridPane.columnIndex="5"/>
<Button fx:id="btn4" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="4" GridPane.rowIndex="1"/>
<Button fx:id="btn5" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="5" GridPane.columnIndex="1"
GridPane.rowIndex="1"/>
<Button fx:id="btn6" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="6" GridPane.columnIndex="2"
GridPane.rowIndex="1"/>
<Button fx:id="btnMultiply" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="x" GridPane.columnIndex="4"
GridPane.rowIndex="1"/>
<Button fx:id="btn1" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="1" GridPane.rowIndex="2"/>
<Button fx:id="btn2" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="2" GridPane.columnIndex="1"
GridPane.rowIndex="2"/>
<Button fx:id="btn3" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="3" GridPane.columnIndex="2"
GridPane.rowIndex="2"/>
<Button fx:id="btn0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
mnemonicParsing="false" text="0" GridPane.columnSpan="2"
GridPane.rowIndex="3"/>
<Button fx:id="btnDecimal" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="." GridPane.columnIndex="2"
GridPane.rowIndex="3"/>
<Button fx:id="btnSubtract" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="-" GridPane.columnIndex="4"
GridPane.rowIndex="2"/>
<Button fx:id="btnAdd" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="+" GridPane.columnIndex="4"
GridPane.rowIndex="3"/>
<Button fx:id="btnEquals" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="="
GridPane.columnIndex="5" GridPane.rowIndex="2" GridPane.rowSpan="2"/>
<Button fx:id="btnBackspace" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
mnemonicParsing="false" prefHeight="50.0" prefWidth="50.0" text="←" GridPane.columnIndex="5"
GridPane.rowIndex="1"/>
</children>
</GridPane>
</children>
</VBox>
MainController.java:
import javafx.application.Platform;
import javafx.css.PseudoClass;
import javafx.fxml.FXML;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
public class MainController {
// Here we'll define our PseudoClass needed to set the style for each pressed Button
private static final PseudoClass PRESSED = PseudoClass.getPseudoClass("pressed");
// Define FXML controls
#FXML
private TextField txtDisplay;
#FXML
private Button btn7, btn8, btn9;
#FXML
private Button btn4, btn5, btn6;
#FXML
private Button btn1, btn2, btn3;
#FXML
private Button btn0, btnDecimal;
#FXML
private Button btnMultiply, btnSubtract, btnAdd, btnDivide;
#FXML
private Button btnClear, btnEquals, btnBackspace;
#FXML
private void initialize() {
// We need access to the Scene to register our key listeners, so we need to wrap the code in a Platform.runLater(). If we try to do this without Platform.runLater(), we'll get a NullPointerException because txtDisplay hasn't been rendered yet.
Platform.runLater(() -> {
Scene scene = txtDisplay.getScene();
// Add a listener to capture any key that is pressed. We add this to the entire scene and we can then change the style of the corresponding button accordingly.
scene.setOnKeyPressed(event -> {
// We need to know which Button we're working with
Button button = getButton(event.getCode());
// Add our "pressed" style to the Button
if (button != null) button.pseudoClassStateChanged(PRESSED, true);
});
// Once the user releases the key, remove our custom style and trigger whatever onAction() code has been applied to the corresponding Button.
scene.setOnKeyReleased(event -> {
Button button = getButton(event.getCode());
if (button != null) {
button.pseudoClassStateChanged(PRESSED, false);
// Fire the button's onAction()
button.fire();
}
});
});
}
// Helper method to get the Button that corresponds to the pressed key. The Scene.setOnKeyPressed() listener provides the KeyCode for the pressed key. We can use that to determine which of our Buttons to trigger.
private Button getButton(KeyCode keyCode) {
switch (keyCode) {
case NUMPAD0: return btn0;
case NUMPAD1: return btn1;
case NUMPAD2: return btn2;
case NUMPAD3: return btn3;
case NUMPAD4: return btn4;
case NUMPAD5: return btn5;
case NUMPAD6: return btn6;
case NUMPAD7: return btn7;
case NUMPAD8: return btn8;
case NUMPAD9: return btn9;
case DECIMAL: return btnDecimal;
case DIVIDE: return btnDivide;
case ADD: return btnAdd;
case MULTIPLY: return btnMultiply;
case SUBTRACT: return btnSubtract;
case ENTER: return btnEquals;
case BACK_SPACE: return btnBackspace;
case ESCAPE: return btnClear;
}
return null;
}
}
style.css:
.text-field {
-fx-opacity: 1.0;
-fx-font-family: Consolas;
-fx-font-size: 200%;
}
.button {
-fx-font-family: Consolas;
-fx-font-size: 150%;
-fx-background-radius: 25px;
-fx-border-radius: 25px;
/* Remove focus highlighting */
-fx-focus-traversable: false;
}
.button:pressed {
-fx-background-color: lightgreen;
-fx-border-color: green;
}
And here is the result:
Related
I'm working on a desktop application using javaFX, I'm using scene builder version 11 to create my interface that contains TextFields and ChoiceBox, my inputs are supposed to be set in Arabic. The problem is when I retrieve the text from the TextFiled or the ChoiceBox and print it in the console it shows characters like that "بننلنلن" and it also generates a problem to store the inputs in database, this is the SQLException:
java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'بننلنلن,نبلنبنلب,2021-06-30,أمر جزائي,تم التبليغ
When I tried another project without scene builder I got the Arabic outputs correctly, could scene bulider be the problem's origin?
here is my fxml file:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ChoiceBox?>
<?import javafx.scene.control.DatePicker?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<AnchorPane id="AnchorIns" prefHeight="529.0" prefWidth="523.0" stylesheets="#newinsc.css" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="newInsc.NewInscController">
<children>
<VBox fx:id="boxContainer" layoutX="139.0" layoutY="99.0" prefHeight="273.0" prefWidth="245.0">
<children>
<HBox alignment="CENTER_RIGHT" prefHeight="42.0" prefWidth="245.0">
<children>
<TextField fx:id="firstNameTxtField" alignment="CENTER_RIGHT" />
<Label alignment="CENTER_RIGHT" contentDisplay="RIGHT" prefHeight="17.0" prefWidth="71.0" stylesheets="#newinsc.css" text="الاسم" />
</children>
</HBox>
<HBox alignment="CENTER_RIGHT" prefHeight="42.0" prefWidth="245.0">
<children>
<TextField fx:id="lastNameTxtField" alignment="CENTER_RIGHT" />
<Label prefHeight="17.0" prefWidth="71.0" text="اللقب" />
</children>
</HBox>
<HBox alignment="CENTER_RIGHT" prefHeight="42.0" prefWidth="245.0">
<children>
<ChoiceBox fx:id="docTypeChoice" prefWidth="150.0" />
<Label prefHeight="17.0" prefWidth="71.0" text="نوع التبليغ" />
</children>
</HBox>
<HBox alignment="CENTER_RIGHT" prefHeight="42.0" prefWidth="245.0">
<children>
<DatePicker fx:id="dateField" prefHeight="25.0" prefWidth="149.0" />
<Label prefHeight="17.0" prefWidth="71.0" text="التاريخ" />
</children>
</HBox>
<HBox alignment="CENTER_RIGHT" prefHeight="42.0" prefWidth="245.0">
<children>
<ChoiceBox fx:id="tablighCase" prefWidth="150.0" />
<Label prefHeight="17.0" prefWidth="71.0" text="حالة التبليغ" />
</children>
</HBox>
<HBox alignment="CENTER" onMouseClicked="#cancelBtnClicked" prefHeight="46.0" prefWidth="245.0">
<children>
<Button fx:id="cancleBtn" mnemonicParsing="false" onMouseClicked="#cancelBtnClicked" text="الغاء">
<HBox.margin>
<Insets right="16.0" />
</HBox.margin>
</Button>
<Button fx:id="saveInscBtn" mnemonicParsing="false" onMouseClicked="#registerBtnClicked" text="تسجيل" />
</children>
</HBox>
</children>
</VBox>
</children>
</AnchorPane>
and this here is my controller file:
package newInsc;
import DB.dbConnection;
import java.net.URL;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.time.LocalDate;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.DatePicker;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
/**
* FXML Controller class
*
* #author asus
*/
public class NewInscController implements Initializable {
#FXML
private ChoiceBox<String> docTypeChoice;
#FXML
private ChoiceBox<String> tablighCase;
#FXML
private DatePicker dateField;
#FXML
private Button saveInscBtn;
#FXML
private TextField firstNameTxtField;
#FXML
private TextField lastNameTxtField;
#FXML
private Button cancleBtn;
private Connection c;
private Statement s;
#FXML
private VBox boxContainer;
#Override
public void initialize(URL url, ResourceBundle rb) {
docTypeChoice.getItems().add("أمر جزائي");
docTypeChoice.getItems().add("حكم جزائي" );
docTypeChoice.getItems().add("تكليف بالحضور" );
docTypeChoice.getItems().add("قرار جزائي" );
tablighCase.getItems().add("تم التبليغ");
tablighCase.getItems().add("ترك اشعار");
tablighCase.getItems().add("عدم التمكن من التبليغ");
}
#FXML
private void cancelBtnClicked(MouseEvent event) {
Stage s = (Stage) cancleBtn.getScene().getWindow();
}
#FXML
private void registerBtnClicked(MouseEvent event) {
try {
String query;
String fname = firstNameTxtField.getText();
String lname = lastNameTxtField.getText();
LocalDate date = dateField.getValue();
String docType = docTypeChoice.getValue();
String state = tablighCase.getValue();
query = "insert into infotable values " + fname + "," + lname + "," + date+ ","+ docType+"," +state ;
dbConnection dbc = new dbConnection();
s = dbc.createConnection().createStatement();
s.execute(query);
s.close();
} catch (SQLException ex) {
Logger.getLogger(NewInscController.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
I could find a solution, before I run the program I first compile it with F9 key then I run it with a key combination SHIFT + F6
I'm tryin to follow the material design guide for my application's color scheme. At the moment, I'm at the part where it's explaining how the dark theme works.
This is my CSS:
#main-app {
-fx-background-color: #121212;
-fx-background-radius: 5px;
}
#top-bar {
-fx-background-color: bar-color;
-fx-background-radius: 5px 5px 0 0;
}
#bottom-bar {
-fx-background-color: bar-color;
-fx-background-radius: 0 0 5px 5px;
}
How can I do the 5% overlay, as seen in the image below, of my #main-app's background-color so I can then apply it to the top and bottom bars?
I give it another shot ;-)
CSS File:
#main-app {
-fx-background-radius: 5px;
-fx-background-color: #121212;
}
#top-bar {
-fx-background-radius: 5px 5px 0 0;
-fx-background-color: inherit;
}
#top-bar-overlay {
-fx-background-radius: 5px 5px 0 0;
-fx-background-color: rgba(255, 255, 255, 0.05);
}
#bottom-bar {
-fx-background-radius: 0 0 5px 5px;
-fx-background-color: inherit;
}
#bottom-bar-overlay {
-fx-background-radius: 0 0 5px 5px;
-fx-background-color: rgba(255, 255, 255, 0.5);
}
FXML File:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Spinner?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.text.Font?>
<AnchorPane stylesheets="#styling2.css" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.OverlayController">
<children>
<HBox alignment="CENTER_LEFT" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<Label text="Transparency Value for Top Bar Overlay:" />
<Spinner fx:id="topBarTransparencySpinner" />
<Label text="Transparency Value for Bottom Bar Overlay:" />
<Spinner fx:id="bottomBarTransparencySpinner" />
</children>
</HBox>
<GridPane id="main-app" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="27.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" />
</columnConstraints>
<rowConstraints>
<RowConstraints vgrow="SOMETIMES" />
<RowConstraints vgrow="SOMETIMES" />
</rowConstraints>
<children>
<AnchorPane id="top-bar">
<children>
<HBox id="top-bar" alignment="CENTER" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<Label text="Top Bar">
<font>
<Font size="36.0" />
</font>
<HBox.margin>
<Insets />
</HBox.margin>
</Label>
</children>
</HBox>
<Pane id="top-bar-overlay" fx:id="topBarOverlayPane" mouseTransparent="true" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
</AnchorPane>
<AnchorPane GridPane.rowIndex="1">
<children>
<HBox id="bottom-bar" alignment="CENTER" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<Label text="Bottom Bar">
<font>
<Font size="36.0" />
</font>
</Label>
</children>
</HBox>
<Pane id="bottom-bar-overlay" fx:id="bottomBarOverlayPane" mouseTransparent="true" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
</AnchorPane>
</children>
</GridPane>
</children>
</AnchorPane>
Controller Class:
package sample;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Spinner;
import javafx.scene.control.SpinnerValueFactory;
import javafx.scene.layout.Pane;
import java.net.URL;
import java.util.ResourceBundle;
public class OverlayController implements Initializable {
#FXML
Spinner<Double>
topBarTransparencySpinner,
bottomBarTransparencySpinner;
#FXML
private Pane
topBarOverlayPane,
bottomBarOverlayPane;
#Override
public void initialize(URL location, ResourceBundle resources) {
topBarTransparencySpinner.setValueFactory(new SpinnerValueFactory.DoubleSpinnerValueFactory(0, 1, 0.05, 0.01));
bottomBarTransparencySpinner.setValueFactory(new SpinnerValueFactory.DoubleSpinnerValueFactory(0, 1, 0.5, 0.01));
topBarTransparencySpinner.valueProperty().addListener((obs, oldV, newV) ->
topBarOverlayPane.setStyle(String.format("-fx-background-color: rgba(255, 255, 255, %s);", String.valueOf(newV).replace(",", "."))));
bottomBarTransparencySpinner.valueProperty().addListener((obs, oldV, newV) ->
bottomBarOverlayPane.setStyle(String.format("-fx-background-color: rgba(255, 255, 255, %s);", String.valueOf(newV).replace(",", "."))));
}
}
Preview:
Does this example help you for your project?
If you main background is already black, I think you can use an rgba background-color on the blocks. So for a 5% white overlay rgba(255,255,255,0.05).
I'm not sure if this is what you looking for but I hope it can help you a bit.
I think that it is not possible with css only. Here is one example for a possible solution:
Controller Class:
package sample;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.Pane;
import java.net.URL;
import java.util.ResourceBundle;
public class Controller implements Initializable {
#FXML
private FlowPane rootFlowPane;
#Override
public void initialize(URL location, ResourceBundle resources) {
for (int i = 0; i < rootFlowPane.getChildren().size(); i++) {
Node node = rootFlowPane.getChildren().get(i);
if (node instanceof Pane) {
Pane pane = (Pane) node;
String style = "-fx-background-color: rgba(255, 255, 255, %s); -fx-background-radius: 5; -fx-border-color: grey;";
if (i == 0)
pane.setStyle(String.format(style, "0"));
else if (i == 1)
pane.setStyle(String.format(style, "0.05"));
else if (i == 2)
pane.setStyle(String.format(style, "0.07"));
else if (i >= 100)
pane.setStyle(String.format(style, "1"));
else {
String transparency = String.format("%.2f", (i + 5) / 100.0).replace(",", ".");
pane.setStyle(String.format(style, transparency));
}
}
}
}
}
FXML File:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.FlowPane?>
<?import javafx.scene.layout.Pane?>
<FlowPane fx:id="rootFlowPane" hgap="20.0" prefHeight="460.0" prefWidth="460.0" style="-fx-background-color: #121212;" vgap="20.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<children>
<Pane prefHeight="200.0" prefWidth="200.0" />
<Pane prefHeight="200.0" prefWidth="200.0" />
<Pane prefHeight="200.0" prefWidth="200.0" />
<Pane prefHeight="200.0" prefWidth="200.0" />
</children>
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
</padding>
</FlowPane>
Preview:
I'm writing a program which consists of two different scenes, each one is designed with an FXML file and each of them has its own controller. My initial scene works fine, and it appears in the center of the screen, but when I try to load the second scene from the controller of the first one, I get that it doesn't appears in the center of the screen like the other one does.
Can anyone please help me? It is freaking me out!
Here's some code:
#Override
public void start(Stage primaryStage) {
try {
//Create an FXMLLoader
FXMLLoader rootLoader = new FXMLLoader(getClass().getResource("MainScene.fxml"));
//Instantiate a new controller with parameter and sets it to the FXMLLoader
MainController mainController = new MainController(primaryStage);
rootLoader.setController(mainController);
//Sets the layout
Group root = rootLoader.load();
Scene startScene = new Scene(root);
//Sets the stage's scene
primaryStage.initStyle(StageStyle.TRANSPARENT);
primaryStage.setScene(startScene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
This is from the Main.
public void initialize() {
FXMLLoader playSceneLoader = new FXMLLoader(getClass().getResource("PlayScene.fxml"));
try {
Group playSceneLayout = playSceneLoader.load();
playScene = new Scene(playSceneLayout, Screen.getPrimary().getBounds().getMaxX(), Screen.getPrimary().getBounds().getMaxY());
playScene.setFill(Color.TRANSPARENT);
} catch (IOException e) {
e.printStackTrace();
}
}
This is from the first controller which create the initial scene of the program.
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.Group?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.text.Font?>
<Group xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1">
<children>
<GridPane prefHeight="300.0" prefWidth="500.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<AnchorPane prefHeight="200.0" prefWidth="200.0" style="-fx-background-color: #A47888#A47888;">
<children>
<Label fx:id="playLabel" layoutX="90.0" layoutY="129.0" onMouseClicked="#startLabelClicked" text="Play" textFill="#77354c">
<font>
<Font name="AvidOmnes Light" size="41.0" />
</font>
</Label>
</children>
</AnchorPane>
<AnchorPane prefHeight="200.0" prefWidth="200.0" style="-fx-background-color: #77354C#77354C;" GridPane.columnIndex="1">
<children>
<Label fx:id="titleLabel" layoutX="77.0" layoutY="129.0" text="Titolo" textFill="#a47888">
<font>
<Font name="AvidOmnes Light" size="40.0" />
</font>
</Label>
<Label fx:id="closeLabel" layoutX="232.0" layoutY="6.0" onMouseClicked="#closeRoot" text="X" textFill="#a47888" />
</children>
</AnchorPane>
</children>
</GridPane>
</children>
</Group>
This is the FXML file of the initial page.
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.Group?>
<?import javafx.scene.shape.Circle?>
<Group xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.PlayController">
<children>
<Circle fx:id="startCircle" fill="DODGERBLUE" onMouseClicked="#startCircleClicked" radius="100.0" stroke="BLACK" strokeType="INSIDE" />
</children>
</Group>
And this is the second scene's one.
That's absolutely normal that you get only a slice of your Circle as you do not define center coordinate and then is by default located in the position (0, 0) of the Group.
In order to see it in top-left corner of your screen, you have to maximize your Stage as soon as you click on your Label.
Here is an example: (as you were stingy of information about your code I improvise, so the important modification is in the startLabelClicked)
public class MainController {
private Stage mainStage;
private Scene playScene;
public MainController(Stage pMainStage) {
mainStage = pMainStage;
}
#FXML
public void initialize() {
FXMLLoader playSceneLoader = new FXMLLoader(getClass().getResource("PlayScene.fxml"));
try {
Parent playSceneLayout = playSceneLoader.load();
playScene = new Scene(playSceneLayout, Screen.getPrimary().getBounds().getMaxX(), Screen.getPrimary().getBounds().getMaxY());
playScene.setFill(Color.TRANSPARENT);
} catch (IOException e) {
e.printStackTrace();
}
}
#FXML
private void startLabelClicked() {
mainStage.setScene(playScene);
// This line will help you to extend your stage, which contains your scene.
mainStage.setMaximized(true);
}
#FXML
private void closeRoot() {
System.out.println("Closing.");
Platform.exit();
}
}
Without adjusting the x and y properties of the circle, the center of the circle is positioned at the top left of the scene. Since javafx does not display anything outside of the scene, you're left with the bottom right quater of a circle.
To display a circle completely in a scene with in the top left corner of a scene, you should put the circle in a layout that does some layout. E.g. AnchorPane with topAnchor and leftAnchor properties set for the circle would work, but the simplest way of accomplishing the desired result is to use a StackPane with a top left alignment:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.shape.Circle?>
<StackPane alignment="TOP_LEFT" xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.PlayController">
<children>
<Circle fx:id="startCircle" fill="DODGERBLUE" onMouseClicked="#startCircleClicked" radius="100.0" stroke="BLACK" strokeType="INSIDE" />
</children>
</StackPane>
I made a TextField in FXML. I want to add Button in this TextField like clear button. How can I implement this?
You could use an AnchorPane to wrap the TextField and the Button and set the anchors to have the TextField to fill the entire AnchorPane and the Button to be anchored to the right-side.
Example:
<AnchorPane prefHeight="24.0" prefWidth="322.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<TextField prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
<Button graphicTextGap="0.0" minHeight="10.0" minWidth="13.0" mnemonicParsing="false" prefHeight="20.0" prefWidth="22.0" style="-fx-background-color: #7085FF;
-fx-background-radius: 30;
-fx-background-insets: 0;" text="x" textFill="WHITE" AnchorPane.bottomAnchor="4.0" AnchorPane.rightAnchor="4.0" AnchorPane.topAnchor="4.0">
<font>
<Font size="9.0" />
</font>
</Button>
</children>
</AnchorPane>
The output is like:
If you need it more than once (and most probably you will), it is a good idea to have it separately in another FXML file with the corresponding controller class that also handles the action of the Button.
Example with separated FXML:
ButtonedTextField.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.*?>
<?import javafx.scene.text.Font?>
<AnchorPane xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="application.ButtonedTextField">
<children>
<TextField fx:id="textField" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
<Button fx:id="button" graphicTextGap="0.0" minHeight="10.0" minWidth="13.0" mnemonicParsing="false" prefHeight="20.0" prefWidth="22.0" style="-fx-background-color: #7085FF;
-fx-background-radius: 30;
-fx-background-insets: 0;" text="x" textFill="WHITE" AnchorPane.bottomAnchor="4.0" AnchorPane.rightAnchor="4.0" AnchorPane.topAnchor="4.0">
<font>
<Font size="9.0" />
</font>
</Button>
</children>
</AnchorPane>
ButtonedTextField.java (controller)
public class ButtonedTextField implements Initializable {
public #FXML TextField textField;
private #FXML Button button;
#Override
public void initialize(URL location, ResourceBundle resources) {
button.setOnAction(e -> textField.setText(""));
}
}
And then you can include this control to another FXML:
ButtonedTextFieldTest.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.layout.*?>
<TabPane xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="application.ButtonedTextFieldTest">
<tabs>
<Tab text="Untitled Tab">
<content>
<AnchorPane id="Content" minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
<children>
<fx:include fx:id="buttonedTextField" source="ButtonedTextField.fxml" prefWidth="200.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="2.0" />
</children>
</AnchorPane>
</content>
</Tab>
</tabs>
</TabPane>
ButtonedTextFieldTest.java (controller of including FXML)
public class ButtonedTextFieldTest implements Initializable {
private #FXML AnchorPane buttonedTextField;
private #FXML ButtonedTextField buttonedTextFieldController;
#Override
public void initialize(URL location, ResourceBundle resources) {
buttonedTextFieldController.textField.textProperty().addListener((ov, oldVal, newVal) -> {
System.out.println(newVal);
});
}
}
Notes:
You can customize the Button as you wish (maybe it is the easier to set the graphic)
The placement and the styling can be further customized.
As you can see in the last class, the control itself and its controller can be also injected! The convention is to have the controller injected is to use the "Controller" postfix after the ID of the inected control.
I have used the CustomTextField class from the ControlsFX project for this kind of functionality before. ControlsFX lacks good documentation, but the CustomTextField class is quite easy to use:
CustomTextField textfield = new CustomTextField
textfield.setRight(new Button());
So the Button look normal when the program starts but If the decrease the size the window with my cursor horizontally or vertically, the buttons shrink to a smaller size.
Code
FXML File
<?import java.lang.*?>
<?import java.net.*?>
<?import javafx.scene.shape.*?>
<?import javafx.scene.text.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.image.*?>
<?import java.net.URL?>
<VBox fx:id="OptionMenuLayout" alignment="TOP_CENTER" spacing="15" prefWidth="1366" prefHeight="768" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.40" fx:controller="millionairetriviagame.OptionscreenController">
<stylesheets>
<URL value="#BackgroundImages.css" />
</stylesheets>
<stylesheets>
<URL value="#ButtonLayout.css" />
</stylesheets>
<children>
<ImageView fitHeight="300" fitWidth="300" smooth="true" >
<image>
<Image url="#ImageFiles/MillionaireLogo1.png" />
</image>
</ImageView>
<Label style="-fx-font-style: Italic;" text="Click to Change the Background Color" textFill="white">
<font>
<javafx.scene.text.Font name="sans-serif" size="20" />
</font>
</Label>
<HBox alignment="CENTER" spacing="200">
<children>
<Button id="SmallBlueBackground1" fx:id="optionButton1" onAction="#changeBackgroundScreen" prefHeight="50" prefWidth="80" />
<Button id="SmallBlueBackground2" fx:id="optionButton2" onAction="#changeBackgroundScreen" prefHeight="50" prefWidth="80" />
<Button id="SmallBlueBackground3" fx:id="optionButton3" onAction="#changeBackgroundScreen" prefHeight="50" prefWidth="80" />
</children>
</HBox>
<Region prefHeight="200.0" prefWidth="200.0" VBox.vgrow="ALWAYS" />
<HBox alignment="BOTTOM_RIGHT" spacing="10">
<children>
<Button fx:id="backToMain" onAction="#goToTheMainMenu" prefHeight="30" prefWidth="200" id="ButtonLayout" text="Back to the Main Menu">
<shape>
<javafx.scene.shape.Rectangle arcHeight="30" arcWidth="30" height="30" width="200" />
</shape>
</Button>
</children>
</HBox>
</children>
</VBox>
Here is a screenshot: Note that I resized the screen with my cursor to show this as this is right not the size of the screen
As you can see, the buttons are not their regular size.
Here is the CSS file(if need be) associated with the 3 main buttons that you see in the screenshot
#BlueBackground1
{
-fx-background-image: url("/millionairetriviagame/ImageFiles/BlueBackgroundColor.jpg");
-fx-smooth: true;
-fx-background-position: center center;
}
#BlueBackground2
{
-fx-background-image: url("/millionairetriviagame/ImageFiles/BlueBackgroundColor2.jpg");
-fx-smooth: true;
-fx-background-position: center center;
}
#BlueBackground3
{
-fx-background-image: url("/millionairetriviagame/ImageFiles/BlueBackgroundColor3.jpg");
-fx-smooth: true;
-fx-background-position: center center;
}
#SmallBlueBackground1
{
-fx-background-image: url("/millionairetriviagame/ImageFiles/BlueBackgroundColor.jpg");
-fx-background-repeat: stretch;
-fx-background-size: 80 50;
-fx-background-position: center center;
-fx-background-insets: 0, 0, 0, 0;
-fx-border-color: black;
-fx-border-width: 3;
-fx-border-style: solid;
-fx-effect: dropshadow(three-pass-box, black, 5, 0.5, 0, 0);
}
#SmallBlueBackground2
{
-fx-background-image: url("/millionairetriviagame/ImageFiles/BlueBackgroundColor2.jpg");
-fx-background-repeat: stretch;
-fx-background-size: 80 50;
-fx-background-position: center center;
-fx-background-insets: 0, 0, 0, 0;
-fx-border-color: black;
-fx-border-width: 3;
-fx-border-style: solid;
-fx-effect: dropshadow(three-pass-box, black, 5, 0.5, 0, 0);
}
#SmallBlueBackground3
{
-fx-background-image: url("/millionairetriviagame/ImageFiles/BlueBackgroundColor3.jpg");
-fx-background-repeat: stretch;
-fx-background-size: 80 50;
-fx-background-position: center center;
-fx-background-insets: 0, 0, 0, 0;
-fx-border-color: black;
-fx-border-width: 3;
-fx-border-style: solid;
-fx-effect: dropshadow(three-pass-box, black, 5, 0.5, 0, 0);
}
If you want to have dynamic dimensions you shouldn't use min/pref/max size. Instead you should use proper layout containers. For your example you could use e. g. a
VBox for the entire screen
a top and a bottom Stackpane in that VBox
a GridPane in the bottom Stackpane for the buttons
and let the button dimensions be computed.
Something like this:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.shape.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1">
<children>
<StackPane VBox.vgrow="ALWAYS" />
<StackPane VBox.vgrow="ALWAYS">
<children>
<GridPane hgap="10.0" vgap="10.0">
<columnConstraints>
<ColumnConstraints hgrow="ALWAYS" />
<ColumnConstraints hgrow="ALWAYS" />
</columnConstraints>
<rowConstraints>
<RowConstraints vgrow="ALWAYS" />
<RowConstraints vgrow="ALWAYS" />
</rowConstraints>
<children>
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" text="Button" GridPane.hgrow="ALWAYS" />
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" text="Button" GridPane.columnIndex="1" GridPane.hgrow="ALWAYS" />
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" text="Button" GridPane.hgrow="ALWAYS" GridPane.rowIndex="1" />
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" text="Button" GridPane.columnIndex="1" GridPane.hgrow="ALWAYS" GridPane.rowIndex="1" />
</children>
<StackPane.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</StackPane.margin>
</GridPane>
</children>
</StackPane>
</children>
</VBox>
Note: The "1.7976931348623157E308" values are MAX_VALUE in scene builder.
Set min size on the button like pref size. That should work.
#edit: And you could set the resizable attribute to false