cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Browse apps to extend the software in the new JMP Marketplace
Choose Language Hide Translation Bar

How to generate buttons within a loop?

I'm trying to generate buttons within a loop (one button for each column). The buttons are created correctly except that when the button executes its script it will always execute the script of the lastly created button - instead of the script that was passed to the button box object when it was created.

So, it seems that the button gets only a reference to the script - and if script is changed the button will change its function. I tried considering workaround with array of scripts but the problem is that I can't pass any argument for the button object (e.g. index which script in the array to execute).

Question: Is there any way in jsl that one can create buttons within a loop with different scripts/behaviour? E.g. is there any way of passing arguments/data to button object when it is created???

My code:

NamesDefaultToHere(1);

dt = Current Data Table();

dtCols = dt << Get Column Names( Numeric, Continuous );

// Expression for displaying distribution for strParam

Expr_ShowDistribution = Expr(

  New Window( Char(strParam),

    Distribution(

      Continuous Distribution(

         Column( strParam ) //We specify our parameter

      ),

      SendToReport(

         Dispatch( {}, "Distribution", OutlineBox, Set Title( "" ) ),

      )

    )

  )

);

// Main Window

New Window("Main Window",

  ob = OutlineBox("Buttons",

       TextBox("Debugging buttons", Set Font Style("Bold"))

  );

);

// Create button that only outputs to log

BB = Button Box( "ClickMe", Show("Clicked"));

ob << Append(BB);

// Create buttons for showing distributions

For( i = 1, i <= NItems(dtCols), i++,

  Expr_ButtonAction = Substitute(NameExpr(Expr_ShowDistribution),

     Expr(strParam), Eval(Char(dtCols)) );


  Show(NameExpr(Expr_ButtonAction)); // Expression is different for each button.

  BB = Button Box( Char(dtCols), Eval(Expr_ButtonAction));

  ob << Append(BB);

);

2 ACCEPTED SOLUTIONS

Accepted Solutions
pmroz
Super User

Re: How to generate buttons within a loop?

Here's an implementation that works.  I changed the distribution expression to a function, and then had to play with evalinsert, parse, eval to get it to work.

showdistribution = function({column_name}, {Default Local},

     dist_expr = evalinsert(

"\[Distribution( Nominal Distribution( column(:name("^column_name^")) ) )]\");

     eval(parse(dist_expr));

);

// Main Window

New Window("Main Window",

  ob = OutlineBox("Buttons",

       TextBox("Debugging buttons", Set Font Style("Bold"))

  );

);

// Create button that only outputs to log

BB = Button Box( "ClickMe", Show("Clicked"));

ob << Append(BB);

dt = open("$sample_data\Big Class.jmp");

dtcols = dt << get column names(string);

for (i = 1, i <= nitems(dtcols), i++,

     button_expr = evalinsert("\[one_button = button box("^dtcols^", showdistribution("^dtcols^"))]\");

     eval(parse(button_expr));

     ob << append(one_button);

);

View solution in original post

ms
Super User (Alumni) ms
Super User (Alumni)

Re: How to generate buttons within a loop?

Your example should work if the last two rows within the loop, i.e

BB = Button Box( Char(dtCols[i]), Eval(Expr_ButtonAction));

  ob << Append(BB);

are replaced with

Eval( Eval Expr( ob << Append( Button Box( Char( dtCols[i] ), Expr( Name Expr( Expr_ButtonAction ) ) ) ) ) );

Not the most obvious solution. Here, I think the "string manipulation" approach like in PMroz' example is simpler. 

View solution in original post

5 REPLIES 5
pmroz
Super User

Re: How to generate buttons within a loop?

Here's an implementation that works.  I changed the distribution expression to a function, and then had to play with evalinsert, parse, eval to get it to work.

showdistribution = function({column_name}, {Default Local},

     dist_expr = evalinsert(

"\[Distribution( Nominal Distribution( column(:name("^column_name^")) ) )]\");

     eval(parse(dist_expr));

);

// Main Window

New Window("Main Window",

  ob = OutlineBox("Buttons",

       TextBox("Debugging buttons", Set Font Style("Bold"))

  );

);

// Create button that only outputs to log

BB = Button Box( "ClickMe", Show("Clicked"));

ob << Append(BB);

dt = open("$sample_data\Big Class.jmp");

dtcols = dt << get column names(string);

for (i = 1, i <= nitems(dtcols), i++,

     button_expr = evalinsert("\[one_button = button box("^dtcols^", showdistribution("^dtcols^"))]\");

     eval(parse(button_expr));

     ob << append(one_button);

);

Craige_Hales
Super User

Re: How to generate buttons within a loop?

A button script can be a function with a "this" parameter that refers to the button, which means the button can find its name or its parent box.

New Window( "example", v = V List Box() );

f = Function( {this}, Show( this << getbuttonname ) );

For( i = 1, i < 10, i++,

  v << append( Button Box( "number " || Char( i ), Set Function( f ) ) )

);

7422_Buttons.PNG

The "Set Function" parameter is the key to making this work.  In your example I think the button names might be the column names.  The VListBox in the example is named "v" so button boxes can be appended to it. 

Craige
Eric_Hill
Staff

Re: How to generate buttons within a loop?

The Set Function() approach would seem to be more useful if I could attach some user data to the button, say by adding key-value pairs to an associative array.  Is that possible?

Craige_Hales
Super User

Re: How to generate buttons within a loop?

Good idea, but not implemented.  For now I'd suggest using the button's name as the key to an associative array.

Craige
ms
Super User (Alumni) ms
Super User (Alumni)

Re: How to generate buttons within a loop?

Your example should work if the last two rows within the loop, i.e

BB = Button Box( Char(dtCols[i]), Eval(Expr_ButtonAction));

  ob << Append(BB);

are replaced with

Eval( Eval Expr( ob << Append( Button Box( Char( dtCols[i] ), Expr( Name Expr( Expr_ButtonAction ) ) ) ) ) );

Not the most obvious solution. Here, I think the "string manipulation" approach like in PMroz' example is simpler.