- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Get Direct Link
- Report Inappropriate Content
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 ) )
)}
)
);
*/
Accepted Solutions
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Get Direct Link
- Report Inappropriate Content
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 ) ) )
)}
)
))
);
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Get Direct Link
- Report Inappropriate Content
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)^"))
);
);
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Get Direct Link
- Report Inappropriate Content
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 ) ) )
)}
)
))
);
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Get Direct Link
- Report Inappropriate Content
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 ) || "\!"))") )
}
);
);
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Get Direct Link
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Get Direct Link
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Get Direct Link
- Report Inappropriate Content
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)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Get Direct Link
- Report Inappropriate Content
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)^"))
);
);