A question arose recently: can we move the Help menu item to the right edge of the active window?
In an earlier post, I looked at some basics of Menu-related controls in ScalaFX, and wrote some simple code for ScalaFX to create a basic menu bar that looked like this:
Our three Menus are all left-aligned, which is pretty standard in the realm of desktop applications.
So: does ScalaFX give us the controls and hooks that we need in order to adjust the alignment and push the last menu to be Right-aligned?
After browsing the ScalaFX API, the only alignment-related tools I noticed applied to the entire MenuBar. I did not notice anything that provided the ability to alter the alignment on a per-Menu basis.
Next, I wondered if we could set the horizontal-growth property on a Menu. If so, we could specify the last of the left-aligned Menus to have the highest priority for Horizontal stretching, which could push any Menus that followed it to the right edge of the MenuBar area.
The method HBox.setHgrow() is promising, but it acts on a Node in an HBox layout. Two issues: my basic menu above is not using HBox layout; and even if it were, Menu is not a descendant of Node.
MenuBar, on the other hand, does inherit from Node. So let's try using two MenuBars laid out in an HBox. Something like this:
val menuCore = new MenuBar {
menus = List(
new Menu("_File") {
mnemonicParsing = true
items = List(
new MenuItem("New..."),
new MenuItem("Save")
)
},
new Menu("_Edit") {
mnemonicParsing = true
items = List(
new MenuItem("Cut"),
new MenuItem("Copy"),
new MenuItem("Paste")
)
}
)
}
val menuHelp = new MenuBar {
menus = List (
new Menu("_Help") {
mnemonicParsing = true
items = List(
new MenuItem("About")
)
}
)
}
val menuAll = new HBox {
children = List(menuCore, menuHelp)
}
HBox.setHgrow(menuCore, Priority.Always)
val wholeLayout = new VBox {
children = List(menuAll)
}
Previously, I had a single MenuBar with three Menu items added. Now, I have pulled the third one, the Help menu, out into a separate MenuBar object. I then created an HBox to lay them out side by side, and used HBox.setHgrow() to specify that any extra horizontal space be given to the menuCore object.
Then the whole HBox layout was added to a VBox as before. Here is the result:
Nice! That's the layout I was aiming for, with the main two Menus on the far left, and the Help Menu off by itself on the far right. And they keep that layout as the window is resized.
There is just one minor problem with this solution: while it visually looks like one big MenuBar, it is actually two MenuBars. It looks good and will behave correctly when users interact with it using mouse or touch-screen input. But keyboard input presents some navigation issues.
For example, when I hit the ALT-key, which normally activates a Menu on a MenuBar, this happens:
With two MenuBar objects, they both get activated by the ALT-key.
There are also some unexpected interactions when I use the keyboard arrow keys to navigate the Menus and MenuItems. I don't expect they will be insurmountable show-stoppers, but if I want to keep this two-MenuBar solution, I will have to do some work with keyboard events, to make sure that the navigation behaves as expected.
In an earlier post, I looked at some basics of Menu-related controls in ScalaFX, and wrote some simple code for ScalaFX to create a basic menu bar that looked like this:
Our three Menus are all left-aligned, which is pretty standard in the realm of desktop applications.
So: does ScalaFX give us the controls and hooks that we need in order to adjust the alignment and push the last menu to be Right-aligned?
After browsing the ScalaFX API, the only alignment-related tools I noticed applied to the entire MenuBar. I did not notice anything that provided the ability to alter the alignment on a per-Menu basis.
Next, I wondered if we could set the horizontal-growth property on a Menu. If so, we could specify the last of the left-aligned Menus to have the highest priority for Horizontal stretching, which could push any Menus that followed it to the right edge of the MenuBar area.
The method HBox.setHgrow() is promising, but it acts on a Node in an HBox layout. Two issues: my basic menu above is not using HBox layout; and even if it were, Menu is not a descendant of Node.
MenuBar, on the other hand, does inherit from Node. So let's try using two MenuBars laid out in an HBox. Something like this:
val menuCore = new MenuBar {
menus = List(
new Menu("_File") {
mnemonicParsing = true
items = List(
new MenuItem("New..."),
new MenuItem("Save")
)
},
new Menu("_Edit") {
mnemonicParsing = true
items = List(
new MenuItem("Cut"),
new MenuItem("Copy"),
new MenuItem("Paste")
)
}
)
}
val menuHelp = new MenuBar {
menus = List (
new Menu("_Help") {
mnemonicParsing = true
items = List(
new MenuItem("About")
)
}
)
}
val menuAll = new HBox {
children = List(menuCore, menuHelp)
}
HBox.setHgrow(menuCore, Priority.Always)
val wholeLayout = new VBox {
children = List(menuAll)
}
Previously, I had a single MenuBar with three Menu items added. Now, I have pulled the third one, the Help menu, out into a separate MenuBar object. I then created an HBox to lay them out side by side, and used HBox.setHgrow() to specify that any extra horizontal space be given to the menuCore object.
Then the whole HBox layout was added to a VBox as before. Here is the result:
Nice! That's the layout I was aiming for, with the main two Menus on the far left, and the Help Menu off by itself on the far right. And they keep that layout as the window is resized.
There is just one minor problem with this solution: while it visually looks like one big MenuBar, it is actually two MenuBars. It looks good and will behave correctly when users interact with it using mouse or touch-screen input. But keyboard input presents some navigation issues.
For example, when I hit the ALT-key, which normally activates a Menu on a MenuBar, this happens:
With two MenuBar objects, they both get activated by the ALT-key.
There are also some unexpected interactions when I use the keyboard arrow keys to navigate the Menus and MenuItems. I don't expect they will be insurmountable show-stoppers, but if I want to keep this two-MenuBar solution, I will have to do some work with keyboard events, to make sure that the navigation behaves as expected.