cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
JMP is taking Discovery online, April 16 and 18. Register today and join us for interactive sessions featuring popular presentation topics, networking, and discussions with the experts.
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.