1

I'm trying to set a different style for my Menu Bar, according to the scene background.

All my Controllers have a Pane to load my MenuBar inside.

HomePage.java

public class HomePage implements Initializable {

@FXML
private VBox menuPane;
@FXML
private GridPane gridPane;

@Override
public void initialize(URL location, ResourceBundle resources) {
    Menu menu = new Menu();
    menu.loadMenuBar(menuPane);
    menu.setMenuBarColor("#000"); // PROBLEM HAPPENS HERE
}

And my Menu.Java class

import javafx.scene.control.MenuBar;

public class Menu  {

@FXML
private MenuBar menuBar;

public void loadMenuBar(Pane pane) {
    try {
        pane.getChildren().add(FXMLLoader.load((getClass().getResource("/ui/FXML/Menu.fxml"))));
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public void openHomepage() {
    Stage stage = Main.getPrimaryStage();
    try {
        Parent root = FXMLLoader.load(getClass().getResource("/ui/FXML/HomePage.fxml"));
        changeScene(root);
        stage.setTitle("Some title");
    } catch (IOException e1) {
        e1.printStackTrace();
    }
}

public void setMenuBarColor(String color){
    menuBar.setStyle("-fx-my-menu-color-highlighted: " + color + ";");
}

For this example, I use the HomePage.Java controller, but it works well and my menu is showing on every scene.

I also have my Menu.css :

* {
-fx-my-menu-color: #FFFFFF;
-fx-my-menu-color-highlighted: #006886;
-fx-my-menu-font-color: #000;
-fx-my-menu-font-color-highlighted: #fff;
}


.menu-bar {
-fx-background-color: -fx-my-menu-color;
}

The problem is, I want to change the background of my MenuBar (by changing the CSS variable '-fx-my-menu-color'), but no matter what I try, it does either nothing, or throws a NullPointerException.

EDIT: clearer examples with "setMenuBarColor()" and stacktrace:

    javafx.fxml.LoadException: 
/U:/Developpement/IntelliJ/Statistiques/out/production/Statistiques/ui/FXML/HomePage.fxml

    at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2601)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2579)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441)
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2409)
    at main.Main.start(Main.java:35)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$161(LauncherImpl.java:863)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$174(PlatformImpl.java:326)
    at com.sun.javafx.application.PlatformImpl.lambda$null$172(PlatformImpl.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$173(PlatformImpl.java:294)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$147(WinApplication.java:177)
    at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.NullPointerException
    at main.Menu.setMenuBarColor(Menu.java:35)
    at main.HomePage.initialize(HomePage.java:38)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2548)
    ... 12 more

Menu.fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.Cursor?>
<?import javafx.scene.control.Menu?>
<?import javafx.scene.control.MenuBar?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.control.SeparatorMenuItem?>
<?import javafx.scene.input.KeyCodeCombination?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane prefHeight="0.0" prefWidth="663.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="main.Menu">
    <MenuBar fx:id="menuBar" layoutY="2.0" opacity="0.9" prefHeight="0.0" prefWidth="663.0" stylesheets="@../CSS/Menu.css">
        <cursor>
            <Cursor fx:constant="DEFAULT" />
        </cursor>
        <Menu mnemonicParsing="false" style="-fx-font-weight: bold;" styleClass="menu-title" text="STATISTIQUES">
            <MenuItem accelerator="backspace" mnemonicParsing="false" onAction="#openHomepage" style="-fx-font-weight: normal;" text="Revenir à l'accueil          " />
            <SeparatorMenuItem mnemonicParsing="false" />
         <MenuItem mnemonicParsing="false" onAction="#openSettings" text="Paramètres" />
            <MenuItem mnemonicParsing="false" onAction="#showPatchnote" style="-fx-font-weight: normal;" text="Patchnote" />
            <MenuItem mnemonicParsing="false" onAction="#changeLogs" style="-fx-font-weight: normal;" text="Changelogs" />
            <SeparatorMenuItem mnemonicParsing="false" />
            <MenuItem accelerator="Shortcut+Q" mnemonicParsing="false" onAction="#closeButtonAction" style="-fx-font-weight: normal;" text="Quitter Statistiques" />
        </Menu>
        <Menu mnemonicParsing="false" text="Fichier">
            <MenuItem mnemonicParsing="false" onAction="#print" text="Imprimer" />
        </Menu>
        <Menu mnemonicParsing="false" text="Edit">
            <MenuItem accelerator="Shortcut+Z" mnemonicParsing="false" text="Annuler" />
            <MenuItem accelerator="Shortcut+Y" mnemonicParsing="false" text="Rétablir" />
            <SeparatorMenuItem mnemonicParsing="false" />
            <MenuItem disable="true" mnemonicParsing="false" text="Préférences" />
        </Menu>
        <Menu mnemonicParsing="false" text="Département AVJ">
         <MenuItem mnemonicParsing="false" onAction="#openSelectAvj" text="Menu de sélection" />
            <MenuItem mnemonicParsing="false" onAction="#openContingentPage" text="Contingent" />
            <SeparatorMenuItem mnemonicParsing="false" />
            <MenuItem mnemonicParsing="false" onAction="#openASDB" text="ASDB Engine" />
        </Menu>
        <Menu mnemonicParsing="false" text="Département SI">
         <MenuItem mnemonicParsing="false" onAction="#openSelectSi" text="Menu de sélection" />
            <MenuItem mnemonicParsing="false" onAction="#openIndicateursPage" text="Indicateurs annuels" />
            <MenuItem mnemonicParsing="false" onAction="#openComparaisonAnnees" text="Comparaison années" />
         <MenuItem mnemonicParsing="false" onAction="#openComparaisonCentres" text="Comparaison centres" />
            <MenuItem disable="true" mnemonicParsing="false" text="Comparaison régions" />
            <Menu mnemonicParsing="false" onAction="#openSelectVisitesPatients" text="Comparaison Visites/Patients">
                <MenuItem mnemonicParsing="false" onAction="#openVisitesCentres" text="Visites / Centres"/>
                <MenuItem mnemonicParsing="false" onAction="#openVisitesLocalites" text="Visites / Localités"/>
                <SeparatorMenuItem mnemonicParsing="false"/>
                <MenuItem disable="true" mnemonicParsing="false" text="Patients / Centres"/>
                <MenuItem disable="true" mnemonicParsing="false" text="Patients / Localités"/>
            </Menu>
            <SeparatorMenuItem mnemonicParsing="false" />
            <Menu mnemonicParsing="false" text="Rapports">
                <MenuItem mnemonicParsing="false" onAction="#pdfActivite" text="Rapport d'activité" />
            <MenuItem mnemonicParsing="false" onAction="#pdfGestion" text="Rapport indicateurs de gestion" />
            </Menu>
        </Menu>
        <Menu mnemonicParsing="false" text="Outils">
            <MenuItem mnemonicParsing="false" onAction="#openASDB" text="ASDB Engine" />
         <MenuItem mnemonicParsing="false" onAction="#detectJavaVersion" text="JAVA Version">
            <accelerator>
               <KeyCodeCombination alt="UP" code="J" control="DOWN" meta="UP" shift="UP" shortcut="UP" />
            </accelerator></MenuItem>
         <MenuItem mnemonicParsing="false" onAction="#openConnectionTest" text="Tester les connexions">
            <accelerator>
               <KeyCodeCombination alt="UP" code="T" control="DOWN" meta="UP" shift="UP" shortcut="UP" />
            </accelerator></MenuItem>
        </Menu>
        <Menu mnemonicParsing="false" text="?">
            <MenuItem disable="true" mnemonicParsing="false" text="Aide" />
            <MenuItem disable="true" mnemonicParsing="false" text="Signaler un bug" />
            <SeparatorMenuItem mnemonicParsing="false" />
            <MenuItem mnemonicParsing="false" onAction="#openAboutWindow" text="À propos de Statistiques" />
        </Menu>
    </MenuBar>
</AnchorPane>
Playlist
  • 37
  • 7
  • Please post stacktrace message, and FXML code. – thefern Apr 25 '19 at 14:00
  • Here you are. Added clearer example with a 'setMenuBarColor()' method. – Playlist Apr 26 '19 at 08:34
  • Do you happen to have this project on github, or somewhere online? If not please zip and share link on post. I think I have an idea of what's going on, could be the MenuBar reference not assigned properly or FXML not loading. The CSS looks fine. If you don't want to share I can post a quick working example of menu bar color change. – thefern Apr 26 '19 at 11:33
  • There are a lot of private information about the company so I couldn't really share this, but I would love to see a working example. – Playlist Apr 29 '19 at 08:48

1 Answers1

1

I found the issue after looking at your code, and other javafx examples from oracle. The problem boils down that you cannot change your custom css variables from setStyle. From setStyle method you can only override css properties available on caspian.css which is the java default css. (Line 802 for menu properties, and then menu-bar follows).

The easiest fix to do here is to call the correct property from setStyle:

Issue:

public void setMenuBarColor(String color){
    menuBar.setStyle("-fx-my-menu-color-highlighted: " + color + ";");
}

Fix:

public void setMenuBarColor(String color){
    menuBar.setStyle("-fx-background-color: " + color + ";");
}

You can combine both setStyle, and using a css file just make sure you don't set properties for the same selector.

Below is a quick example: MenuExample.java

package sample;  

import javafx.application.Application;  
import javafx.scene.Scene;  
import javafx.scene.control.Menu;  
import javafx.scene.control.MenuBar;  
import javafx.scene.layout.VBox;  
import javafx.stage.Stage;  

public class MenuExample extends Application {  

  public static void main(String[] args) {  
  launch(args);  
  }  

  @Override  
 public void start(Stage primaryStage) {  
  primaryStage.setTitle("JavaFX App");  

  Menu menu1 = new Menu("Menu 1");  

  MenuBar menuBar = new MenuBar();  

  menuBar.getMenus().add(menu1);  
  //menuBar.setStyle("-fx-background-color: #6601C6;");  //uncomment to use this instead of css
  //menu1.setStyle("-fx-background-color: #FF7F11;");  
  VBox vBox = new VBox(menuBar);  

  Scene scene = new Scene(vBox, 960, 600);  
  scene.getStylesheets().add("sample/sample-menu.css"); // comment here if using setStyle


  primaryStage.setScene(scene);  
  primaryStage.show();  
  }  
}

sample-menu.css

/* VARIABLE DEFINITIONS: Only these 4 variables have to be adjusted, the rest is copy-paste */  
* {  
    -fx-my-menu-color: #00ff00;                  /* Change according to your needs */  
  -fx-my-menu-color-highlighted: #FF7F11;      /* Change according to your needs */  
  -fx-my-menu-font-color: #FFFFFF;             /* Change according to your needs */  
  -fx-my-menu-font-color-highlighted: #FFFFFF; /* Change according to your needs */  
}  

/* Try this: Comment .menu below and use menu1.setStyle from MenuExample.java */  
.menu {  
    -fx-background-color: #FF7F11;  
}  

/* MENU BAR + Top-level MENU BUTTONS */  
/*** The menu bar itself ***/  
.menu-bar {  
    -fx-background-color: -fx-my-menu-color;  
}  

/* CONTEXT MENU */  
/*** The context menu that contains a menu's menu items ***/  
.context-menu {  
    -fx-background-color: -fx-my-menu-color;  
}

There is a way to set CSS variables by using pseudoclass, but I think for what you are doing here is just make sense to change that one method. I've never used the peudoclass so I can't speak how it would work once the CSS is loaded at runtime.

References:

SO: How to set styles

SO: PseudoClass

thefern
  • 367
  • 7
  • 19