2

I am working on custom styling for my application. My current problem stems from the fact that designers specified entirely different styles for menu bar and menu items. I implemented the button style, but menu popup now slightly overlays the button itself (including button label), which is ugly.

Is there some way to control menu popup position relatively to menu bar button? Where is the code that actually positions those popups? I searched through JavaFX source, but javafx.scene.control.Menu class does not handle anything related to context menus - seems that menu logic happens in some entirely different place.

Rogach
  • 26,050
  • 21
  • 93
  • 172

3 Answers3

2

I believe the popups from the menu is done with ContextMenu (the same as right clicking menu). You will also be able to change the location using CSS. You can also use ScenicView and SceneBuilder to extensively debug your GUI and find the appropriate CSS paths (if you are not already doing so).

The relevant css classes can be found here How can I style a JavaFX menu and its items in CSS? and padding and margin can be used to move the context menu.

Check out the default CSS style called Modena. Line 1166 is where the menu stuff starts.

Hope this helps.

UPDATE:

Here is my test: enter image description here

As it turns out, the context menu pops up at the bottom of the menu button. As far as I know there is no way to MOVE the actual node via CSS.

This means, as it overlaps for you, the menu button is not as big as your menubar, if you make it as big as your menubar (as I did in the picture) it will appear perfectly under the menubar.

As you can see, instead of using padding on the menubar, I use it on the menu buttons. This will automatically resize the menubar and cause the contextmenu to pop up perfectly in place.

I have also removed the color to show you that it is fully transparent if you remove the color.

As you can see here: enter image description here

-fx-effect: null; also removes the default shadow effect. If you want more extensive control over this, you will need to implement your own menu buttons and your own context menu. Only then, you will have full control.

Community
  • 1
  • 1
Limnic
  • 1,826
  • 1
  • 20
  • 45
  • Yes, using CSS will be ideal. But how? I know about -fx-padding, but I can't find -fx-margin anywhere in the docs. – Rogach Sep 15 '15 at 05:47
  • -fx-margin is actually insets. For example, -fx-background-insets. I believe that is the one you want to use. – Limnic Sep 15 '15 at 10:00
  • I tried -fx-background-insets, and it didn't help - the popup is still firmly in the same place. – Rogach Sep 15 '15 at 10:32
  • Usually when I cannot find something, I look at the default CSS style Modena. Check my post I have included a link to the stuff you want. – Limnic Sep 15 '15 at 10:41
  • Still, applying -fx-background-insets and -fx-border-insets doesn't help - I still have white border around popup. – Rogach Sep 15 '15 at 10:51
  • ... what do you mean white border around popup? You never talked about that before. – Limnic Sep 15 '15 at 22:11
  • I mean that if I specify something like "-fx-background-insets: 5px; -fx-border-insets: 5px", I can see how border and background really move "inside" the popup, but there is additional white stripe around the border. – Rogach Sep 16 '15 at 10:25
  • I think I will really go with my own menu buttons and context menus, since that really will make things much easier – Rogach Sep 16 '15 at 10:26
  • But wait, I found where the code for actual showing resides! MenuButton has skin (MenuButtonSkin by default), which has method `show()`, which actually fine-tunes context menu position. I'll try extending the skin and maybe that will give me the needed result. – Rogach Sep 16 '15 at 11:15
  • Yes, you could do that and it will work. The CSS can only do so much. As you can see, for basic movement (via padding) it works fine but if you cannot use that for any reason then you have to do it via your own implementation. – Limnic Sep 16 '15 at 12:49
2

The actual code for showing the popup is located in MenuButtonSkinBase:

private void show() {
    if (!popup.isShowing()) {
        popup.show(getSkinnable(), getSkinnable().getPopupSide(), 0, 0);
    }
}

Two last parameters to popup.show are X and Y offset of popup. Unfortunately, method is marked as private for some reason, so it is not possible to simply create a subclass of MenuButtonSkin and override that method.

One possible solution is to copy-paste code from MenuButtonSkinBase and MenuButtonSkin into your own file (about 300 lines of code) and tweak the method there. After that, you will be able to do:

menuButton.setSkin(new TweakedMenuButtonSkin(menuButton));
Rogach
  • 26,050
  • 21
  • 93
  • 172
1

You dont need to copy the whole skin. If you extend the skin you can change this fairly easily (even though the method is private). Just copy paste the following.... (change the position to whatever you want in the "show" method)

@Override
protected void handleControlPropertyChanged(String p) {
    if ("SHOWING".equals(p)) {
        if (getSkinnable().isShowing()) {
            show();
        } else {
            super.handleControlPropertyChanged(p);
        }
    } else {
        super.handleControlPropertyChanged(p);
    }
}


private void show() {
    if (!popup.isShowing()) {
        popup.show(getSkinnable(), getSkinnable().getPopupSide(), 100, 100);
    }
}
CodeMnke
  • 96
  • 4