Smart Client Menu Bar methods

Questions and answers on designing your Servoy solutions, database modelling and other 'how do I do this' that don't fit in any of the other categories

Smart Client Menu Bar methods

Postby CFDaddy » Wed Feb 04, 2015 7:59 pm

I have some enum's setup as arrays that contain the menu structure for the menu items in the Smart Client Menu Bar. The menu is drawn out prefectly, icons show, etc. The issue is with passing in the method for the menu item. For example, here is the array that contains the menu item information for the Exit item:

Code: Select all
['Exit',      'exitSolution',   [],   'general/clean_general_cross_16.png',   null,   true]


Where the array is structured as follows:

Code: Select all
[name {String}, feedback_item {Method}, feedback_args {Array}, icon {String}, mnemonic {String}, enabled {Boolean}]


When creating the menu item with the following code:

Code: Select all
_jsMenuItem = _jsMenu.addMenuItem(_jsMenuItemArr[0],_jsMenuItemArr[1]);


I get the following error:

Can't find method com.servoy.extensions.plugins.window.menu.AbstractMenu.js_addMenuItem(string,string). (C:\workspace\solution\globals.js#100)
Can't find method com.servoy.extensions.plugins.window.menu.AbstractMenu.js_addMenuItem(string,string). (C:\workspace\solution\globals.js#100)
at C:\workspace\solution\globals.js:100 (onSolutionOpen_SmartClient)

Interestingly, if I create the menu item like this instead:

Code: Select all
_jsMenuItem = _jsMenu.addMenuItem(_jsMenuItemArr[0]);
_jsMenuItem.setMethod(_jsMenuItemArr[1]);


I get a different error that shows in a popup onSolutionOpen that states:

Method/Function is null

So, how can I get the method name I want to call into the addMenuItem function and be sure that I can call methods that are dynamic enough to either be contained in a form OR in a scope? For instance, if I have the exitSolution method in scopes.myutils I need to be able to specify that in the array as "scopes.myutils.exitSolution" or if it is in a form I would need to call it as "forms['myform']['exitSolution']".

Thanks!
Keith L. Miller
Director of Technology
ProjecTools
4099 Hwy 36 North, Bellville, Texas 77418
P 713.371.9840 x1601 F 713.371.9841
E millerk@projectools.com W www.projectools.com
User avatar
CFDaddy
 
Posts: 75
Joined: Mon Aug 15, 2011 7:12 pm
Location: Bellville, TX USA

Re: Smart Client Menu Bar methods

Postby CFDaddy » Wed Feb 04, 2015 11:44 pm

So I've made "some" progress BUT I don't think it is the correct way to make this work. What I've done is made use of the dreaded 'eval()' function. So, my array looks like this:

Code: Select all
['Exit',      'scopes.scopeName.exitSolution',   [],   'general/clean_general_cross_16.png',   null,   true]


OR

Code: Select all
['Exit',      'forms.frmName.exitSolution',   [],   'general/clean_general_cross_16.png',   null,   true]


and my code to make it works is this:

Code: Select all
/** @type {Function} */
var _jsMenuItemMethod = null;


then a little further down inside the loop that is reading the array I have this:

Code: Select all
_jsMenuItemMethod = eval(_jsMenuItemArr[1]);
_jsMenuItem = _jsMenu.addMenuItem(_jsMenuItemArr[0],_jsMenuItemArr[1]);


however, I get a warning on the line with the eval() statement that says:

"The function eval(String) is not applicable for the arguments (Boolean|Array<empty>|String)"

Everything works when the solution is launched, but how do I get rid of the Servoy warning? Better yet, how can I accomplish this without the use of eval() if possible?

Thanks!
Keith L. Miller
Director of Technology
ProjecTools
4099 Hwy 36 North, Bellville, Texas 77418
P 713.371.9840 x1601 F 713.371.9841
E millerk@projectools.com W www.projectools.com
User avatar
CFDaddy
 
Posts: 75
Joined: Mon Aug 15, 2011 7:12 pm
Location: Bellville, TX USA

Re: Smart Client Menu Bar methods

Postby mboegem » Thu Feb 05, 2015 10:03 am

Hi Keith,

Your post consists of 2 problems:
1) the build marker on your code indicating the parameter you pass do not match the signature of the addMenuItem function.
2) the error you get when executing your code

Most of the times problem 1 is the reason for problem 2.

In your case you build the Array which you pass per position.
The problem here is Servoy not being able to determine different types of values within an Array.
So either your array is a String-Array (Array<String>/String[]) or Number-Array(Array<Number>/Number[]), but it can't be a mixture.
Your array structure:
Code: Select all
[name {String}, feedback_item {Method}, feedback_args {Array}, icon {String}, mnemonic {String}, enabled {Boolean}]

Can be build, but Servoy can't handle it in JSDocs, but should still work.

The reason your code fails is that your parameters don't match the docs you posted (which are consistent with the signature of the addMenuItem function)
The 2nd position should hold the actual Function(method), not a string. So this should work:
Code: Select all
['Exit',      scopes.scopeName.exitSolution,   [],   'general/clean_general_cross_16.png',   null,   true]


Getting back to your build marker, how to get rid of it:
Easy way is adding @SuppressWarnings(wrong parameters) to the function header.
A better way might be to store your menu information into an object which Servoy will be able to recognise the types
Code: Select all
function setupMenu() {
   
   /** @type{{name:String, method:Function}} */
   var _item = function(_sName, _method) {
      this.name = _sName;
      this.method = _method;
   }
   
   /** @type{Array<_item>} */
   var _jsMenuItemArr = [new _item('Exit',      exitSolution)];
   
   var _menu = plugins.window.getMenuBar().addMenu();
   _menu.addMenuItem(_jsMenuItemArr[0].name,_jsMenuItemArr[0].method);
}


Hope this helps
Marc Boegem
Solutiative / JBS Group, Partner
• Servoy Certified Developer
• Servoy Valued Professional
• Freelance Developer

Image

Partner of Tower - The most powerful Git client for Mac and Windows
User avatar
mboegem
 
Posts: 1743
Joined: Sun Oct 14, 2007 1:34 pm
Location: Amsterdam

Re: Smart Client Menu Bar methods

Postby huber » Sat Jun 09, 2018 10:28 am

Hi Marc

I tried your suggestion to overcome the problem with eval(), but I can't get it to work. It looks like the types of menuItem properties this.name and this.method are not recognised.

My code looks like:
Code: Select all
   <some code here>
   ...
   var menuBar = plugins.window.getMenuBar();
   menuBar.getMenu(3).text = 'i18n:hades.menu.reports';
   menuBar.getMenu(3).removeAllItems(); // Remove all Reports (renamed Select) menu items
   
   /** @type{{name: String, method: Function}} */
   var menuItem = function(pName, pMethod) {
      this.name = pName;
      this.method = pMethod;
   }
            
   var reportsMenu = menuItemParameters;
   var reportsMenuLength = reportsMenu.length;
   
   for (i = 0; i < reportsMenuLength; i++) {
      var reportName = reportsMenu[i][0];
      var reportMethod = reportsMenu[i][1];
      
      /** @type{Array<menuItem>} */
      var menuItemArr = [new menuItem(reportName, reportMethod)];

//      /** @type {Function} */
//      var reportMethod = eval(reportsMenu[i][1]);
   
      if (reportName == 'i18n:hades.rpt.menu.dividerLine') {
         menuBar.getMenu(3).addSeparator(); // Add a separator line to the Reports menu
      }
      else {      
//         menuBar.getMenu(3).addMenuItem(reportName, reportMethod); // Add a menu item to the Reports menu
         menuBar.getMenu(3).addMenuItem(menuItemArr[0].name, menuItemArr[0].method); // Add a menu item to the Reports menu
      }
   }

It does work using the eval() code (the one which is commented out). The error message I get is as shown in the attachment.

Any idea?

Regards,
Attachments
Screen Shot 2018-06-09 at 10.10.29.png
Screen Shot 2018-06-09 at 10.10.29.png (110.25 KiB) Viewed 2857 times
Robert Huber
7r AG, Switzerland
SAN Developer
http://www.seven-r.ch
User avatar
huber
 
Posts: 516
Joined: Mon May 14, 2012 11:31 pm

Re: Smart Client Menu Bar methods

Postby mboegem » Mon Jun 11, 2018 11:43 am

Hi Robert,

I think you misinterpreted my post here.
The initial posts were about build markers and failing code.

The build marker part was about an Array were we can't tell Servoy per Array position what the type should be.
This is however possible with an object where you can specify per names property, what the data type of that property is.
BUT... what JSDocs doesn't do is actual typecasting.

So if you pass your method a parameter pMethod which obviously is of type String, then assigning that parameter to a property in an object and JSDoc that property as being a Function, won't convert your String into a Function. It just makes the build marker disappear, but it doesn't fix your code.

The reason why your code does work using 'eval', is that 'eval' will evaluate whatever you put in there.
It seems like doing magic, but basically you just pass in 'something' and JS will try to make this into another 'something'
So obviously you are passing a String, which happens to exist as a Function, so JS will sort of typecast your String into a Function.

Since you can't tell the eval function how you want it to evaluate, this is just best guess of JS, it's like asking it to draw a car but don't specify how it should look.
Besides, eval function is slow as it has to rule out options first in order to come up with what JS 'thinks' you want.

Bottom line:
Don't try to 'fix' your parameters/code just before you need it, start way back in the way you pass your parameters.
Something like in the code below

Code: Select all
function onApplicationOpen() {
   changeMenu([{name: 'myCustomMenuItem', method:myMenuItemBehaviour], [name:'myCustomMenuItem2', method:myMenuItemBehaviour2]]);
}

function myMenuItemBehaviour() {
   application.output('this is my custom behaviour of a menu item');
}

function myMenuItemBehaviour2() {
   application.output('this is my 2nd custom behaviour of a menu item');
}

/**
*   @param {Array<{name:String, method:Function}>} menuItemParameters
*//
function changeMenu(menuItemParameters) {
      <some code here>
   ...
   var menuBar = plugins.window.getMenuBar();
   menuBar.getMenu(3).text = 'i18n:hades.menu.reports';
   menuBar.getMenu(3).removeAllItems(); // Remove all Reports (renamed Select) menu items
   
   for (i = 0; i < menuItemParameters.length; i++) {
      if (menuItemParameters[i].name == 'i18n:hades.rpt.menu.dividerLine') {
         menuBar.getMenu(3).addSeparator(); // Add a separator line to the Reports menu
      }
      else {     
         menuBar.getMenu(3).addMenuItem(menuItemParameters[i].name, menuItemParameters[i].method); // Add a menu item to the Reports menu
      }
   }
}



Hope this makes sense.
There's a lot to find on using eval on the internet, for example: https://hashnode.com/post/why-is-using- ... 53w6y9cbm3
Marc Boegem
Solutiative / JBS Group, Partner
• Servoy Certified Developer
• Servoy Valued Professional
• Freelance Developer

Image

Partner of Tower - The most powerful Git client for Mac and Windows
User avatar
mboegem
 
Posts: 1743
Joined: Sun Oct 14, 2007 1:34 pm
Location: Amsterdam


Return to Programming with Servoy

Who is online

Users browsing this forum: Bing [Bot] and 9 guests