JavaFX can't find CSS Class after switching windows - java

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

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

Change the property of a rectangle by using another class JavaFX

I'm working on a project and I want a rectangle to appear when I press a button. However, I want to do this by directing the button click to a different class. Here is what I've tried:
Here is my first class, "Main"
static boolean btnClicked = false;
#Override
public void start(Stage primaryStage) {
Button btn = new Button("Make Popup Visible");
Rectangle menu = new Rectangle(40,40,200,200);
menu.setFill(Color.BLACK);
menu.setOpacity(0);
btn.addEventHandler(MouseEvent.MOUSE_CLICKED,(MouseEvent e) ->{
AddRect.showMenu();
});
if(btnClicked == true) {
menu.setOpacity(1);
}
Group root = new Group();
root.getChildren().addAll(btn, menu);
Scene scene = new Scene(root,400,400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
And my second class, "AddRect"
public class AddRect {
static void showMenu() {
Main.btnClicked = true;
}
}
However, this isn't working, and I don't know why. Can somebody help me? I don't even know if this is the best way to do it (Using two classes), but if there is a better way please let me know. Thanks in advance!
I figured it out! I just had to move the conditional inside the EventHandler
btn.addEventHandler(MouseEvent.MOUSE_CLICKED,(MouseEvent e) ->{
AddRect.showMenu();
if(btnClicked == true) {
menu.setOpacity(1);
}
});

JavaFX UNDECORATED Stage not showing

I've got problem with may e(fx)clipse application. I want to show a splash screen upon application startup. I successfully created class implementing StartupProgressTrackerService, and got my stateReached method invoked. However I've got problems with javafx itself. I want to create Stage with StageStyle.UNDECORATED. However when i invoke stage.show() method stage isn't rendered immediately and appears just after main window is created. It works fine e.g. with StageStyle.UTILITY. It also renders correctly when i use showAndWait() method, but it stops my app from loading until i close the stage.
Here is my code:
public class MyStartupProgressTrackerService implements StartupProgressTrackerService {
private Stage stage;
public MyStartupProgressTrackerService() {
}
#Override
public OSGiRV osgiApplicationLaunched(IApplicationContext applicationContext) {
applicationContext.applicationRunning();
return StartupProgressTrackerService.OSGiRV.CONTINUE;
}
#Override
public void stateReached(ProgressState state) {
if (DefaultProgressState.JAVAFX_INITIALIZED.equals(state)) {
stage = new Stage(StageStyle.UNDECORATED);
stage.initModality(Modality.WINDOW_MODAL);
stage.setAlwaysOnTop(true);
ImageView view = null;
try {
view = new ImageView(SPLASH_IMAGE);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
BorderPane bp = new BorderPane();
bp.getChildren().add(view);
Scene scene = new Scene(bp, 400, 300);
stage.setScene(scene);
stage.show();
}
}
}
I found an ugly solution, but, at least, it works. I noticed that method stage.showAndWait() as a side effect finishes building all controls which haven't been rendered yet. So the trick is to initialize splash screen, and then create dummy stage, showAndWait() it and close() immediately. I know that this solution is far from ideal, so i would appreciate it if someone could show me alternate way to make it work :)
My code:
public void showSplash() {
splashScreen = createSplashScreen();
Stage stage2 = new Stage(StageStyle.TRANSPARENT);
splashScreen.show();
Platform.runLater(new Runnable() {
#Override
public void run() {
stage2.close();
}
});
stage2.showAndWait();
}
private Stage createSplashScreen() {
Stage stage = new Stage(StageStyle.UNDECORATED);
stage.setAlwaysOnTop(true);
VBox vbox = new VBox();
vbox.getChildren().add(new ImageView(splashImage));
Scene scene = new Scene(vbox, 400, 300);
stage.setScene(scene);
return stage;
}

Delay between Preloader and Stage shown

I have a program that uses a simple preloader while the init() method creates the main gui. Everything works fine but after the init() method completes and the preloader disappears, there's a noticeable delay before the main stage shows up. I say noticeable because it can be as much as 7 seconds, enough for a user to get confused.
I tried to put as little as possible in the start() method:
public void start(Stage stage) {
/*Scene*/
scene = new Scene(root, 1200, 700);
stage.setScene(scene);
scene.setFill(null);
/*Stage*/
stage.initStyle(StageStyle.TRANSPARENT);
stage.centerOnScreen();
stage.show();
}
Is there a way to reduce/eliminate this delay? Would it be better to scrap the preloader altogether and implement is as a stage in the main program? Thanks in advance.
EDIT:
I took Maverick283's advice and implemented a fadeOut of the preloader. There was still a bit of delay so I sent the final notification (from the main program to the preloader) after showing the main stage and it worked perfectly!
public void start(Stage stage) {
/*Scene*/
scene = new Scene(root, 1200, 700);
stage.setScene(scene);
scene.setFill(null);
/*Stage*/
stage.initStyle(StageStyle.TRANSPARENT);
stage.centerOnScreen();
stage.show();
notifyPreloader(new Preloader.ProgressNotification(0.99));
}
From Oracle:
The last state change notification received by the preloader before the application starts is StateChangeNotification.Type.BEFORE_START. After it is processed, the application's start() method is called. However, it can take time before the application is ready to display its stage after the start() method is called. If the preloader stage is already hidden, then there could be a period of time when the application shows nothing on the screen.
Thus they provide example code how to fix that:
#Override
public void handleStateChangeNotification(StateChangeNotification evt) {
if (evt.getType() == StateChangeNotification.Type.BEFORE_START) {
if (isEmbedded && stage.isShowing()) {
//fade out, hide stage at the end of animation
FadeTransition ft = new FadeTransition(
Duration.millis(1000), stage.getScene().getRoot());
ft.setFromValue(1.0);
ft.setToValue(0.0);
final Stage s = stage;
EventHandler<ActionEvent> eh = new EventHandler<ActionEvent>() {
public void handle(ActionEvent t) {
s.hide();
}
};
ft.setOnFinished(eh);
ft.play();
} else {
stage.hide();
}
}
}
If you continue reading there is even a way of sharing the two stages (preloader and main application stage)...
I tried the solution shown before but not worked, then I wrote a code that worked for me, what I did was make the preloader dont be hiden by itself, it just get hided when the main app is shown, look:
On Preload:
I commented the stage.hide();
#Override
public void handleStateChangeNotification(StateChangeNotification scn) {
if (scn.getType() == StateChangeNotification.Type.BEFORE_INIT) {
//stage.hide();
}
}
I set stage as static
static Stage stage;
I added this code:
public static Stage getStage() {
return stage;
}
On main app:
#Override
public void start(Stage stage) throws IOException {
scene = new Scene(loadFXML("fxmlLoginGUI.fxml"), 640, 480);
stage.setScene(scene);
stage.show();
if (stage.showingProperty().get()) {
try {
UkhuluvelaERP_Preloader.getStage().hide();
} catch (Exception ex) {
Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
I check if the stage is already shown, then I set the preloader stage to hide() using a get method.
I hope this works for you guys as did for me. good luck. chers

Eliminating Previous Scene After New Scene Is Shown

I am just beginning to learn JAVAFX and I have run into a problem now. I have a login screen and after I clicked login, a dialog box appeared and the problem is I don't know how to eliminate the login screen after the dialog has showed up. Please help me. This is my code
Main.java (contains login screen)
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("../view/LoginScreen.fxml"));
primaryStage.setTitle("Weltes Mart O2 Tank Module");
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
LoginController.java (showing a dialog box)
public class LoginController {
#FXML private Text loginStatusMessage;
#FXML private Button btnLogin;
#FXML public void handleLoginButton(ActionEvent event){
System.out.println("BUTTON PRESSED");
try {
Parent root = FXMLLoader.load(getClass().getResource("../view/LoginSuccessDialog.fxml"));
Stage primaryStage = new Stage();
primaryStage.setScene(new Scene(root));
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
return;
}
}
}
You can use any Node in a Scene to get a reference to that scene. You can use a Scene to get the Window that contains it. You can close that window.
Assuming the Node fields are actually injected by the loader, you can close the Stage using this code:
btnLogin.getScene().getWindow().hide();

Categories

Resources