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
CitizenNo3
Level II

Creating button script in a for loop

I'm trying to generate a table box with a number of row which will be variable. I want each row to have button which will do some function to a corresponding variable in a list. 

 

Current issue: The scripts in the for loop aren't interpreting eval expr as I expect. The resulting script attached to each checkbox should print that button 1, 2, or 3 was pressed. Instead it always says 4. End goal is to do an operation on UserText[i] when the checkbox is clicked.

 

Can anyone help explain what I am doing wrong? Thank you!

 

Bonus question: I'm using check boxes because they are smaller than buttons boxes and button boxes don't seem to be resizable. Ideally they would just be little clickable icons. Is there a friendly way to make a small clickable "x" instead of a full button? 

 

JMP version: 16 

 

Names Default To Here( 1 );

UserText = {"default 1", "default 2", "default 3"};

win2 = New Window( "Select files", 
	tb = Table Box( 
		Col Box( "Text", {} ), 
		Col Box( "Button", {} ), 
		), 
	tb << set row borders(1);
);


//for loop to add a number of rows with a small button next to each one
For( i = 1, i <= N Items( UserText ), i++,
	tb << add row(
		{Text Box( UserText[i], <<set width( 150 ) ), 
		Check Box( "",
			Eval( Eval Expr( Print( "you pressed button " || Char( Expr( i ) ) ) ) )
		)}
	)
);

//this was my first thought, but this creates a script that contains "i" rather than the value of i
/*
For( i = 1, i <= 5, i++,
	tb << add row(
		{Text Box( UserText[i], <<set width( 300 ) ), 
		Check Box( "", 
			Print( "you pressed button " || Char( i ) ) 
		)}
	)
);
*/
2 ACCEPTED SOLUTIONS

Accepted Solutions

Re: Creating button script in a for loop

Hello,

 

You were very close.

 

If you use Eval ( EvalExpr ( ) ) to wrap the entire tb << add row () statement as below, you will get the behavior you're after:

 

//for loop to add a number of rows with a small button next to each one
For( i = 1, i <= N Items( UserText ), i++,
	eval(evalexpr(
		tb << add row(
			{Text Box( UserText[i], <<set width( 150 ) ), 
			Check Box( "",
				Print( "you pressed button " || Char( Expr( i ) ) )
			)}
		)
	))
);

View solution in original post

Re: Creating button script in a for loop

I came back as last night I was thinking, "this can also be done with Xpath and contains". Jarmo's post was already here; the example I've put below is quite similar, but assigns all of the checkbox functions at once with an Xpath statement, once you've built the table. This is becoming one of my favorite ways to handle this type of thing.

 

Names Default To Here( 1 );

UserText = {"default 1", "default 2", "default 3"};

win2 = New Window( "Select files", 
	tb = Table Box( Col Box( "Text", {} ), Col Box( "Button", {} ), << set row borders(1) );
);


//add rows with a small button next to each one
For each ( { txt, i }, UserText,
		tb << add row( {Text Box( txt, <<set width( 150 ) ),  Check Box( "" ) } )
);

// add functions to the checkboxes
(tb << xpath( "//CheckBoxBox") ) << set function(
	function ( {this},
		boxList = (this << parent) << Xpath("//CheckBoxBox");
		print (evalinsert ("You pressed box ^contains(boxList, this)^"))
	);
);

View solution in original post

6 REPLIES 6

Re: Creating button script in a for loop

Hello,

 

You were very close.

 

If you use Eval ( EvalExpr ( ) ) to wrap the entire tb << add row () statement as below, you will get the behavior you're after:

 

//for loop to add a number of rows with a small button next to each one
For( i = 1, i <= N Items( UserText ), i++,
	eval(evalexpr(
		tb << add row(
			{Text Box( UserText[i], <<set width( 150 ) ), 
			Check Box( "",
				Print( "you pressed button " || Char( Expr( i ) ) )
			)}
		)
	))
);
txnelson
Super User

Re: Creating button script in a for loop

Here is my old school way of handling this

Names Default To Here( 1 );
UserText = {"default 1", "default 2", "default 3"};

win2 = New Window( "Select files", 
	tb = Table Box( 
		Col Box( "Text", {} ), 
		Col Box( "Button", {} ), 
		), 
	tb << set row borders(1);
);


//for loop to add a number of rows with a small button next to each one
For( i = 1, i <= N Items( UserText ), i++,
	tb << add row(
		{Text Box( UserText[i], <<set width( 150 ) ), 
		Eval( parse("Check Box( \!"\!",
			 Print( \!"you pressed button " || Char( i ) || "\!"))") ) 
		}
	);
);
Jim
jthi
Super User

Re: Creating button script in a for loop

My method is a bit more complicated using XPath and Contains(), but in some cases it might be more robust (and you can extend it to other elements beside Checkbox if you change the XPath)

Names Default To Here(1);

UserText = {"default 1", "default 2", "default 3"};

win2 = New Window("Select files",
	tb = Table Box(Col Box("Text", {}), Col Box("Button", {}), Col Box("Third", {})),
	tb << set row borders(1)
);

expr_tablebox_get_checkbox_idx = Expr(
	row_idx = Contains((this << parent) << XPath("//CheckBoxBox"), this);
);

expr_tablebox_get_column_idx = Expr(
	col_idx = Contains(((this << parent) << parent) << Get Names, (this << parent) << get heading)
);

expr_check_box = Expr(
	expr_tablebox_get_checkbox_idx;
	expr_tablebox_get_column_idx;
	Show(row_idx, col_idx);
);

For Each({txt}, UserText,
	tb << Add Row(
		{Text Box(txt, << Set Width),
			cb = Check Box({""}, << Set Function(function({this},
					expr_check_box
				))
			),
			cb = Check Box({""}, << Set Function(function({this},
					expr_check_box
				))
			)
		};
	);
);

Using this method you might run into some issues where expressions evaluated correctly depending where you call them, so it shouldn't be the first method to try

 

-Jarmo
CitizenNo3
Level II

Re: Creating button script in a for loop

Thank you! I'll need to spend a bit more time understanding this one, I haven't used set function and I'm not quite understanding the behavior after a quick reading of the scripting guide and some examples. I do foresee a situation down the line where I'll need functionality like this so I'll put this in back of mind for a bit and return if that time comes. 

 

To confirm something basic that doesn't seem to be explicitly stated in the material: when defining a function, is 'this' a pre-defined term in JSL that will point to whatever object the function is attached to? I see some examples that use 'this' in the set function argument without is appearing anywhere else in the function definition (I'm about 60% sure I'm using the correct terms). The basic mathematical functions are intuitive such as MyFn = function ({x,y}, x + y ), but then things seem to ramp up in complexity very quickly when we get into objects. 

jthi
Super User

Re: Creating button script in a for loop

It is just the first parameter when used with << Set Function (as in it doesn't have to be this, seems like JMP17 scripting index is using thisBox for example). And that first argument is a reference to that specific box in which that function is set to.  This help page might provide some more information with some examples:

Scripting Guide > Display Trees > Construct Custom Windows > Set Function and Set Script 

 

Also, with some display boxes you might be able to use multiple parameters with << Set Function . You can see these in scripting index (if you can find them, might be a bit tricky sometimes)

jthi_0-1676528096135.png

 

-Jarmo

Re: Creating button script in a for loop

I came back as last night I was thinking, "this can also be done with Xpath and contains". Jarmo's post was already here; the example I've put below is quite similar, but assigns all of the checkbox functions at once with an Xpath statement, once you've built the table. This is becoming one of my favorite ways to handle this type of thing.

 

Names Default To Here( 1 );

UserText = {"default 1", "default 2", "default 3"};

win2 = New Window( "Select files", 
	tb = Table Box( Col Box( "Text", {} ), Col Box( "Button", {} ), << set row borders(1) );
);


//add rows with a small button next to each one
For each ( { txt, i }, UserText,
		tb << add row( {Text Box( txt, <<set width( 150 ) ),  Check Box( "" ) } )
);

// add functions to the checkboxes
(tb << xpath( "//CheckBoxBox") ) << set function(
	function ( {this},
		boxList = (this << parent) << Xpath("//CheckBoxBox");
		print (evalinsert ("You pressed box ^contains(boxList, this)^"))
	);
);