JavaFX - css does not work in my project - java

I faced with the problem when I can't use the second css file by some evil reason.
I use IntelliJ IDEA 14 (build 139.222) Ultimate edition.
I use JavaFX 2.0 which built-in in IntelliJ IDEA 139.222 build
Board.css does not work. LoginForm.css works fine.
Also I've added the ;?*.css resource pattern into Compiler Section.
btn is the button which I click being at the Login Form.
Instead of GameApp class(it's the class which is inherited from Application class),
I used getClass() method and even some other classes. No result.
the css I tried to use in Board.css is .button:hover {-fx-background-color: white;}
}
Here's the code:
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
Parent root = null;
try {
root = (Pane) FXMLLoader.load(GameApp.class.getResource("/sample/buttonGrid.fxml"));
root.getStylesheets().add(GameApp.class.getResource("/sample/Board.css").toExternalForm());
currentStage.setScene(new Scene(root));
currentStage.setResizable(false);
currentStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
});
#Override
public void start(Stage primaryStage) throws InterruptedException, IOException {
this.currentStage = primaryStage;
primaryStage.setTitle("Hello World");
initPane();
Scene scene = new Scene(grid, 698, 364);
scene.getStylesheets().add(GameApp.class.getResource("LoginForm.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
This one does not work too:
try {
Pane pane = (Pane) FXMLLoader.load(GameApp.class.getResource("/sample/buttonGrid.fxml"));
pane.getStylesheets().add("/sample/Board.css");
currentStage.setScene(new Scene(pane));
currentStage.setResizable(false);
currentStage.show();
}
Board.css is:
.button:hover {
-fx-background-color: white;
}

Earlier versions of JavaFX had some issues adding stylesheets to Parent nodes, instead of adding them to the Scene directly. The code in your action handler for the button adds the stylesheet to the node.
I would recommend making sure you are using a suitably recent version of the JDK and JavaFX; preferably Java 8 (which comes bundled with JavaFX 8). If you are forced to use Java 7, then make sure you have the most recent version, which is bundled with JavaFX 2.2. Simply updating your JDK version may solve the problem.
Also try adding the stylesheet directly to the scene, instead of to the root node:
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
Parent root = null;
try {
root = (Pane) FXMLLoader.load(GameApp.class.getResource("/sample/buttonGrid.fxml"));
Scene scene = new Scene(root);
scene.getStylesheets().add(GameApp.class.getResource("/sample/Board.css").toExternalForm());
currentStage.setScene(scene);
currentStage.setResizable(false);
currentStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
});

Related

How to use JavaFX in Main

I am completly lost atm. I have been working with scenebuilder and javaFX in the past but I am stuck like 5 hours now and I didnt get a step further. Let me explain:
I have a working java Eclipse Project, using maven dependencies
The Main is where I want to use JavaFX or load a fxml into
The programm takes many many VCC Files and extracts the data to put it all together in an excel
The programm works but I cant load a FXML file into the main or even show a pane in there
Now does my Java Main class has to extend Application? I tried both ways - doenst work.
Some example code:
public void start(Stage primaryStage) {
try {
bpmain = new BorderPane(FXMLLoader.load(new File("src\\fxml\\UserInterface.fxml").toURI().toURL()));
primaryStage.setScene(new Scene(bpmain));
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
or this (from original Docs)
public void start(Stage stage) {
Circle circ = new Circle(40, 40, 30);
Group root = new Group(circ);
Scene scene = new Scene(root, 400, 300);
stage.setTitle("My JavaFX Application");
stage.setScene(scene);
stage.show();
}
but this start method is just not getting called... where do I put that?
What my Programm should look like is pretty simple actually. I want a small UI Windows that lets you pick a Folder where the VCC data lives in and a OK Button that basically should run the Main method.
So a TextField that when its picked a Path in the Main gets replaced (filepath) and just a simple OK Button that says: yeah run the main - because the main works perfectly it is just that I cant show that ui and I dont know how to really connect it to the Main.java
Any help is appreciated - Ty
Option 1
public class Launch extends Application {
public static Stage stage = null;
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("/fxml/Main.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
this.stage = stage;
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Option 2:
public class SidebarController implements Initializable {
#Override
public void initialize(URL url, ResourceBundle rb) {
}
#FXML
void btnHome_OnMouseClicked(MouseEvent event) throws IOException {
BorderPane borderPane = (BorderPane) ((Node) event.getSource()).getScene().getRoot();
Parent sidebar = FXMLLoader.load(getClass().getResource("/fxml/ContentArea.fxml"));
borderPane.setCenter(sidebar);
}
}

JavaFX can't find CSS Class after switching windows

I am trying to make a program using JavaFX, unfortunately I have this problem that has been driving me crazy these past hours.
I have created a small program to describe it to you.
The program starts with the Main.java : it boots up the UI.
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
VBox root = (VBox)FXMLLoader.load(getClass().getResource("sanic.fxml"));
Scene scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("app.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.setTitle("sanic");
primaryStage.show();
primaryStage.sizeToScene();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
On the UI, there is just a simple button which leads us to another page:
public class SanicController {
#FXML
public void goesToKnakles(ActionEvent event) {
try {
HBox root = (HBox)FXMLLoader.load(getClass().getResource("knakles.fxml"));
Stage stage = (Stage) ((Node)event.getSource()).getScene().getWindow();
Scene s = new Scene(root);
s.getStylesheets().add(getClass().getResource("app.css").toExternalForm());
stage.setScene(s);
stage.show();
}
catch(Exception e) {
e.printStackTrace();
}
}
}
Simple enough so far.
On this new page, I have this controller:
public class KnaklesController {
#FXML
private HBox box;
public void initialize() {
try {
Label l = new Label("ur my best friend");
l.getStylesheets().addAll("test");
this.box.getChildren().add(l);
}
catch(Exception e) {
e.printStackTrace();
}
}
}
I just have an HBox and I want to add a Label to it.
The Label gets added, however when I want to apply a style to it, Eclipse tells me the following error:
Dec 27, 2017 12:01:48 AM com.sun.javafx.css.StyleManager loadStylesheetUnPrivileged
WARNING: Resource "test" not found.
And finally, here is my CSS:
HBox{
-fx-background-color: #FF00FF;
}
#test {
-fx-background-color: #FFFFFF;
}
Would anyone know WHY the program can't find the appropriate CSS class? This makes me very confused as I have actually successfully applied CSS classes on other parts of my actual program...
If anyone could take the time to solve this I would be extremely grateful.
Alright nevermind I am a goddamn dumbass, it is
getStyleClass()
and not
getStylesheets()

How to parse/map JavaFX CSS file to retrieve its properties and values?

My application allows users to use custom CSS themes to style the interface. I have several pre-built "themes" available to choose from that are very simple, with only 3 properties.
Sample CSS:
.root{
-fx-background: #325c81;
-fx-default-button: #77a3ca;
-fx-base: #a7c4dd;
}
The application has 3 ColorPicker controls that need to allow users to select a color for each of those properties and save back to the CSS file.
I have no problem with actually writing the CSS file, but I cannot find a way to parse the .css file in order to set the values of the ColorPicker controls with the values from the .css file.
Basic Program Flow
1) User selects a premade theme from ComboBox:
cboPresetTheme.valueProperty().addListener((observable, priorTheme, newTheme) -> {
Utility.applyTheme(cboPresetTheme.getScene(), newTheme);
});
2) The associated .css file is loaded and applied to the current Scene:
public static void applyTheme(Scene scene, Theme theme) {
scene.getStylesheets().clear();
File css = new File("themes/" + theme.getFileName());
File fontFile = new File("themes/Font.css");
scene.getStylesheets().addAll(
css.toURI().toString(),
fontFile.toURI().toString());
}
3) The 3 ColorPicker controls are updated with the values from the applied StyleSheet:
cpBackground.setValue(Color.valueOf(cssFileBackground));
cpBase.setValue(Color.valueOf(cssFileBase));
cpDefaultButton.setValue(Color.valueOf(cssFileDefaultButton));
While I have no problem with steps 1 & 2, I do not know how to process step 3.
I have looked at other CSS Parser libraries (thank you, Google) but they seem more geared toward stand CSS and don't support FX properties. The StackExchange question edit or parse FX-CSS file programmatically appears to be asking the same question but it was never successfully answered.
One answer suggests using CSS Parser to accomplish this, but as there is little to know documentation (and what is there is beyond my current comprehension level), I don't know where to begin.
I understand there may not be a standard API currently available to accomplish this, but I was hoping there may be a simple library or solution out there that I have been unable to find.
There are several ways you can tackle the conversion of a CSS declaration into a Color.
Style an auxiliar node
This is quite simple, but effective: The idea is that you could just style the background color of a node with the same css, and then set the colorPicker value with that color.
The only thing you need to take into account in this case is that the node is styled only when is added to a scene.
So you have to add the node to the scene. Adding a node with 0x0 size won't cause any issue, but maybe you don't want it to be there, so you can use an auxiliar scene.
public class CSSParsingApp extends Application {
#Override
public void start(Stage primaryStage) {
ColorPicker cpBackground = new ColorPicker(retrieveColor("value1"));
ColorPicker cpBase = new ColorPicker(retrieveColor("value2"));
ColorPicker cpDefaultButton = new ColorPicker(retrieveColor("value3"));
VBox root = new VBox(10, cpBackground, cpDefaultButton, cpBase);
root.setAlignment(Pos.CENTER);
Scene scene = new Scene(root, 300, 250);
scene.getStylesheets().add(getClass().getResource("style.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
private Color retrieveColor(String value) {
Pane pane = new Pane();
pane.getStyleClass().add(value);
Scene sceneAux = new Scene(pane);
sceneAux.getStylesheets().add(getClass().getResource("style.css").toExternalForm());
pane.applyCss();
return (Color) pane.getBackground().getFills().get(0).getFill();
}
public static void main(String[] args) {
launch(args);
}
}
where style.css is:
.root {
-fx-background: #325c81;
-fx-default-button: #77a3ca;
-fx-base: #a7c4dd;
}
.value1 {
-fx-background-color: -fx-background;
}
.value2 {
-fx-background-color: -fx-default-button;
}
.value3 {
-fx-background-color: -fx-base;
}
Use StylableProperties
A similar, more elegant solution is found here. It uses StylableProperties to create a node, that you can style with a custom -named-color property, and then adds this helper node to the main scene.
Basically it is the same idea as the one above, maybe more clean, as you don't need to modify your css file.
Using CssToColorHelper, your code will be like this:
public class CSSParsingApp extends Application {
private CssToColorHelper helper = new CssToColorHelper();
#Override
public void start(Stage primaryStage) {
ColorPicker cpBackground = new ColorPicker();
ColorPicker cpBase = new ColorPicker();
ColorPicker cpDefaultButton = new ColorPicker();
VBox root = new VBox(10, cpBackground, cpDefaultButton, cpBase, helper);
root.setAlignment(Pos.CENTER);
Scene scene = new Scene(root, 300, 250);
scene.getStylesheets().add(getClass().getResource("style.css").toExternalForm());
cpBackground.setValue(getNamedColor("-fx-background"));
cpDefaultButton.setValue(getNamedColor("-fx-default-button"));
cpBase.setValue(getNamedColor("-fx-base"));
primaryStage.setScene(scene);
primaryStage.show();
}
private Color getNamedColor(String name) {
helper.setStyle("-named-color: " + name + ";");
helper.applyCss();
return helper.getNamedColor();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
where style.css is your css file:
.root {
-fx-background: #325c81;
-fx-default-button: #77a3ca;
-fx-base: #a7c4dd;
}
Use JavaFX CSSParser
If you are looking for a CSSParser, why don't you just use the one included in JavaFX, the one you actually use to apply styling to your app?
It is under com.sun.javafx.css.parser.CSSParser, and if the answer is you don't want to use private API, the good news is that it will be public API in JavaFX 9.
With it you can parse the css file and retrieve any parsed value easily.
public class CSSParsingApp extends Application {
#Override
public void start(Stage primaryStage) {
ColorPicker cpBackground = new ColorPicker();
ColorPicker cpBase = new ColorPicker();
ColorPicker cpDefaultButton = new ColorPicker();
VBox root = new VBox(10, cpBackground, cpDefaultButton, cpBase);
root.setAlignment(Pos.CENTER);
Scene scene = new Scene(root, 300, 250);
scene.getStylesheets().add(getClass().getResource("style.css").toExternalForm());
cpBackground.setValue(parseColor("-fx-background"));
cpDefaultButton.setValue(parseColor("-fx-default-button"));
cpBase.setValue(parseColor("-fx-base"));
primaryStage.setScene(scene);
primaryStage.show();
}
private Color parseColor(String property) {
CSSParser parser = new CSSParser();
try {
Stylesheet css = parser.parse(getClass().getResource("style.css").toURI().toURL());
final Rule rootRule = css.getRules().get(0); // .root
return (Color) rootRule.getDeclarations().stream()
.filter(d -> d.getProperty().equals(property))
.findFirst()
.map(d -> ColorConverter.getInstance().convert(d.getParsedValue(), null))
.get();
} catch (URISyntaxException | IOException ex) { }
return Color.WHITE;
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
where style.css is your css file:
.root {
-fx-background: #325c81;
-fx-default-button: #77a3ca;
-fx-base: #a7c4dd;
}

How do you change the text in a button from another window (JavaFX + FXML)?

I am very new to using JavaFX and have having some trouble using JavaFX with FXML. I am creating a program with a "Setup" button that when clicked, opens a new window with the connection (to an Arduino) settings. On the menu is another button ("Connect") that connects to the board. This closes the window. I'm looking to have this change the text of the original "setup" button to "disconnect", however, I don't seem to be able to access the button from the "setup window". Whenever I click "connect" I get the following error:
Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
I read online that this is a wrapper for a null pointer exception. I assume that the "setup" button is null and that's why I can't change it, but I can't work out why.
Here is an excerpt from MainController.java:
#FXML
protected void setUpConnection(ActionEvent e) {
SetupController setupController = new SetupController();
setupController.init(this);
}
The above method gets called when the "setup" button is clicked (set in the file: setupMenu.fxml). This then opens up the separate window. Here is the code in SetupController.java that opens the window:
private void openSetupWindow() {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("setupMenu.fxml"));
Parent root1 = (Parent)loader.load();
Stage stage = new Stage();
stage.setTitle("Setup Connection");
stage.setScene(new Scene(root1));
stage.show();
} catch(Exception exc) {
exc.printStackTrace();
}
}
When the connect button is clicked, the following method (in SetupController.java) is called:
private void changeButtonText(ConnectionEventType e) {
Button b = main.getSetupButton();
if(e == ConnectionEventType.CONNECT) {
b.setText("Disconnect");
}
else {
b.setText("Setup Connection...");
}
}
(main is the MainController object that was passed in to setupController.init() )
The above code is where I am getting the error.
Just to clarify, I have 2 separate fxml files, one for the main window and one for the pop up. sample.fxml(the main window) has its controller set to MainController and is set up in Main.java (below):
#Override
public void start(Stage primaryStage) throws Exception{
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
GridPane root = loader.load();
Scene scene = new Scene(root, 1200, 900);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setTitle("Nest Control");
primaryStage.setScene(scene);
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
Am I trying to access the button incorrectly? Is anyone able to help? Like I said, I don't have much experience with using JavaFX or FXML.
I think the answer you are looking for is to store the controllers for each window you open so you can access the variables within the controllers, however without the rest of your code would be hard to advise you, but heres an example of what i mean:
private SetupController yourController;
#Override
public void start(Stage primaryStage) throws Exception{
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
GridPane root = loader.load();
this.yourController=loader.<SetupController>getController();
Scene scene = new Scene(root, 1200, 900);
}
}
You could then pass the variable yourController to other instances in a Model-view-controller type way and access its methods.
or something like this in your case :
private void changeButtonText(ConnectionEventType e) {
Button b = this.yourController.getButton(); //a method that returns your #FXML button object in your controller
if(e == ConnectionEventType.CONNECT) {
b.setText("Disconnect");
}
else {
b.setText("Setup Connection...");
}
}
Or alternatively have a specific method within the controller that will set the text of the button without having to return the button object.
See the examples here and here
However please note the error you get seems to typically attributed to missing #FXML annotations so maybe make sure in this instance that you have annotated all the variables in any controllers also. See here for more details.

Set Icon on Stage in JavaFX

I wanted to know how should I set icons on javaFX stage.
I have found this method, but it did not work properly.
stage.getIcons().add(new Image(iconImagePath));
stage is an instance of javafx.stage.Stage, and I have imported javafx.scene.image.Image.
This is the exception which we receive:
Invalid URL: Invalid URL or resource not found
Also, there is nothing wrong with the iconImagePath, its value is "G:/test.jpg"
and there is a jpg file in the G drive named test. In addition, when we use ImageIO to read the same URL we can do it easily.
stage.getIcons().add(new Image(getClass().getResourceAsStream("bal.png")));
This example works. I placed an icon in the same folder/package as the source .java file.
Directory structure
The constructors of javafx.scene.image.Image expect a URI, not a (full) path. This URI can either be relative (e.g. /images/flower.png) or absolute (e.g. file:flower.png).
Strings like G:/test.jpg are no valid URLs and hence illegal.
Try file:g:/test.jpg instead.
Usually, the icons should be bundled with your application, so simply put the image file into your classpath (e.g. if you're using eclipse, put it into your 'src' directory) and use it like that:
stage.getIcons().add(new Image("/logo.jpg"));
use
stage.getIcons().add(new Image(("file:logo.png")));
and put the image logo.png in root of your project ( at same directory where src )
Best Way:
stage.getIcons().add(new Image(getClass().getResource(IconImagePath).toExternalForm()));
don't forget that your icon must be in 32x32 or 16x16 resolution, if not, it doesn't work.
// Set the icon
stage.getIcons().add(new Image(getClass().getResourceAsStream("penguin.png")));
I faced the same problem. I used Netbeans. I'm not sure if the folder structure is different for other IDEs, but I had to put the picture in /build/classes/(package that contains the JavaFX class file). This means it doesn't go into the src folder.
Here is the working code, which is exactly what you neened:
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
/**
*
* #author Manikant gautam
* This is a beginner's sample application
* using JAVAFX
*
*/
public class Helloworld extends Application {
#Override
public void start(Stage primaryStage) {
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Hello World!");
}
});
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root, 300, 250);
// Set Icon From Here.
primaryStage.getIcons().add(
new Image("/resource/graphics/app_logo.png"));
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Set Icon by statement:
primaryStage.getIcons().add(new Image("/resource/graphics/app_logo.png"));
If you're using eclipse make sure you add the folder that has the image to the build path. this way you can refer to the image with its name with no problems.
This is what I've done and it work. The image is located in the root of my resource folder.
stage.getIcons().add(new Image("/ubuntu-mini.png"));
I am using JavaFX 8
I use netbeans 8.2, if I use :
stage.getIcons().addAll(new Image(getClass().getResourceAsStream("home-icon32.png")));
I have to put the image in src directory. Don't know why, but works only this way. I've tried putting it in build/classes, but negative.
The solution is:
File f = new File("image.png");
Image ix = new Image(f.toURI().toString());
stage.getIcons().add(ix);
public class Main extends Application
{
private static final Logger LOGGER = Logger.getLogger(Main.class);
#Override
public void start(Stage primaryStage)
{
try
{
// BorderPane root = new BorderPane();
BorderPane root = (BorderPane) FXMLLoader
.load(getClass().getResource("/org/geeksynergy/view/layout/FrontPageBorder.fxml"));
root.setAccessibleText("good");
Scene scene = new Scene(root, 400, 400);
scene.getStylesheets().add(getClass()
.getResource("/org/geeksynergy/view/cssstyle/application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.setTitle("AiRJuke");
primaryStage.getIcons().add(new Image("/org/geeksymergy/resource/images/download.png"));
primaryStage.show();
AnchorPane personOverview = (AnchorPane) FXMLLoader
.load(getClass().getResource("/org/geeksynergy/view/layout/Ui.fxml"));
root.setCenter(personOverview);
// added this line to save the playlist , when we close
// application window
Platform.setImplicitExit(false);
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>()
{
public void handle(WindowEvent event)
{
M3UPlayList.defaultSavePlaylist();
Platform.setImplicitExit(true);
primaryStage.hide();
}
});
} catch (Exception e)
{
LOGGER.error("Exception while loding application", e);
}
}
public static void main(String[] args)
{
launch(args);
}
}

Categories

Resources