ActionsAndCommands
This interface is NOT USED, it is only here for Documentation.
Glok includes 4 utility classes help separate how : Action, Actions, Command and Commands.
Actions let you define the text, graphics, tooltip and shortcuts for every button, menu and menu item. Commands lets you add the behaviour for a subset of those Actions, and then use it to build the controls.
So instead of :
toolBar {
button( "Save", theSaveGraphic ) { onAction{ saveTheFile() } }
button( "Load", theLoadGraphic ) { onAction{ loadAFile() } } }
subMenu {
menuItem( "Save", theSaveGraphic ) { onAction{ saveTheFile() } }
menuItem( "Load", theLoadGraphic ) { onAction{ loadAFile() } } }
You'd have something like :
val commands = Commands().apply { with( myActions ) { FILE_SAVE { saveTheFile() } FILE_LOAD { loadAFile() } } }
toolBar { with(commands) { with(myActions) {
button(FILE_SAVE)
button(FILE_LOAD) } } }
menuBar { with(commands) { with(myActions) {
menuItem(FILE_SAVE)
menuItem(FILE_LOAD) } } }
Key points :
We have split how buttons behave from how they appear. The GUI building code has no logic code in it.
There is no duplication.
saveTheFile()is only called from one place.I didn't show the extra work needed to handle keyboard shortcuts. Using the first approach, is a PITA, with yet more duplication of calls to
saveTheFile()etc. In the seconds approach, it's as simple as :commands.attachTo( myNode ). The shortcuts will work whenever the input focus is withinmyNode's subtree.Tooltips and menu items will automatically include the keyboard shortcuts. If the user customises these shortcuts, the tooltips and menu items will reflect those changes.
Notes
with(myActions)is only there so that you don't have to use the repetitive :myActions.FILE_SAVE,myActions.FILE_LOADetc.buttonandmenuItemare methods ofCommands, which take anActionas their argument.When writing an I18N application, there is provision for changing language on the fly. Each
Actionhas a singletextProperty, that buttons' and menu items' textProperty is bound to. So to change languages, you need to update textProperty for eachAction. I suggest you bind it like so :action.textProperty.bindTo( translation(languageProperty, text) )Wheretranslationis aStringUnaryFunctionusing resource bundles.To allow users to customise keyboard shortcuts, you'll need to write that GUI yourself. There is no one size fits all solution for this, so I don't intend providing one.