cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Check out the JMP® Marketplace featured Capability Explorer add-in
Choose Language Hide Translation Bar
EvaCo
Level II

Incorrect alignment of checkboxes on the user interface

Hello,
 
I am currently developing a user interface with text and corresponding checkboxes. My code is :
 
strGroupColName = "Group";
lstGroupId = {"A", "B","C","D","E","F","G","H","I","J","K","L"};
strCompareControl = "Compare";
strCompareAddButton = "Add";
strCompareRemoveButton = "Remove";

Compare_String_Col_Box = function({strGroupColName,lstGroupId},

    //Get number of groups
    intNGpId    =     NItems(lstGroupId);

	strStringColBox = 
	"VListBox(
		BorderBox( Bottom(3),
			TextBox(strGroupColName),
		)";
		
	For(ig = 1, ig<= intNGpId, ig++,
		strStringColBox = strStringColBox || ",
		BorderBox( Bottom(3),
			TextBox(\!" " || lstGroupId[ig] || "\!",<<Justify Text( \!"left\!" ),<<Set Wrap(4000 )),
		)";
	);
	strStringColBox = strStringColBox || ")";

	return( eval( parse(strStringColBox) ) );
);

//Run display box containing comparison groups for user interface
winGroupComparison = function({lstGroupId},     
            //Get number of groups
            intNGpId    =     NItems(lstGroupId);

			//Construct string of String Col Box() containing border box to align labels with checkboxes
			strStringColBox = 
			"VListBox(
				BorderBox( Bottom(2),
					TextBox(strGroupColName),
				)";
				
			For(ig = 1, ig<= intNGpId, ig++,
				strStringColBox = strStringColBox || ",
				BorderBox( Bottom(2),
					TextBox(\!" " || lstGroupId[ig] || "\!",<<Justify Text( \!"left\!" ),<<Set Wrap(4000 )),
				)";
			);
			strStringColBox = strStringColBox || ")";
            
            //Construct string of 2 columns (Grp and Ctrl) of check boxes
            strNCheckBox      =     ConcatItems(repeat(list("CheckBox({\!"\!"})"),intNGpId),",");
            strCheckBx        =     "HListBox(  VListBox(TextBox(\!"Grp\!"), "||strNCheckBox||"),
                                                            VListBox(TextBox(\!"Ctrl\!"),"||strNCheckBox||"))";                                       
                                                                                                
            //Initialize to empty list of added comparison columns of check boxes
            lstcomparedpbx = list();
            
            //Script of display box containing all the check boxes and add and remove comparison buttons
            win = "BorderBox(Left(0),Top(20),
                        VListBox(
                        OutlineBox(strCompareControl,
                        HListBox(
                        bbxAdd = ButtonBox(strCompareAddButton,
                                          If(NItems(lstcomparedpbx)==0, lastcompbx = comparedpbx_5, lastcompbx = lstcomparedpbx[NItems(lstcomparedpbx)]);
                                          lastcompbx << SibAppend(BorderBox(Left(10),HListBox(comparedpbx_i = "||strCheckBx||")));
                                          insertinto(lstcomparedpbx,comparedpbx_i);                                                                                                 
                                    ),
                        bbxRemove = ButtonBox(strCompareRemoveButton,
                                          Try(lstcomparedpbx[nitems(lstcomparedpbx)] << delete) ;
                                          lstcomparedpbx = remove(lstcomparedpbx,nitems(lstcomparedpbx));
                                    ))
                        ,
                        BorderBox(Top(20),
                              HListBox(
                                    strcolbx = VListBox(
									Compare_String_Col_Box(strGroupColName,lstGroupId)),
                                    BorderBox(Left(10), HListBox(comparedpbx_1 = "||strCheckBx||")),
                                    BorderBox(Left(10), HListBox(comparedpbx_2 = "||strCheckBx||")),
                                    BorderBox(Left(10), HListBox(comparedpbx_3 = "||strCheckBx||")),
                                    BorderBox(Left(10), HListBox(comparedpbx_4 = "||strCheckBx||")),
                                    BorderBox(Left(10), HListBox(comparedpbx_5 = "||strCheckBx||")),
                        ))
                  )))";
                  
            return( win );
);//end function


groupwin = winGroupComparison(lstGroupId);

Newwindow("Test", eval( parse( groupwin )));

The problem is that the checkboxes are not aligned with the corresponding text, and this issue occurs only on certain computers (same version of JMP used on these different computers). I believe this is due to the different screen sizes. For exemple : 
   
EvaCo_0-1720103409374.pngEvaCo_1-1720103409375.png

 

 
How can I ensure that the checkboxes are always aligned with the text, regardless of the computer being used?
I use JMP 17.2.0
 
Thank you in advance for your help.
1 ACCEPTED SOLUTION

Accepted Solutions
jthi
Super User

Re: Incorrect alignment of checkboxes on the user interface

Like @Jasean already suggested, you can use XPath to get references to all of the CheckBoxBoxes and then send << Get to that. You can then handle that in many different ways, below is other option

Names Default To Here(1);

strGroupColName = "Group";
lstGroupId = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"};
colcount = 5;

nw = New Window("CheckBox UI",
	window:lvals = lstGroupId;
	window:colcount = colcount;
	window:cbs = {};
	Lineup Ruler Box(
		Widths({50,40,45,40,45,40,45,40,45,40,45}),
		lub = Lineup Box(N Col(11));
	);
);

// Add "Headers"
lub << Append(Text Box("Group"));
For(i = 1, i <= colcount, i++,
	lub << Append(Text Box(Eval Insert("Grp(^i^)")));
	lub << Append(Text Box(Eval Insert("Ctrl(^i^)")));
);

// Add "Rows"
For Each({groupid, idx}, lstGroupId,
	lub << Append(Text Box(Eval Insert("^groupid^(^idx^)")));
	For(i = 1, i <= colcount * 2, i++,
		lub << Append(cb = Check Box(""));
	);	
);


// Add functions to check boxes
nw:cbs = nw << XPath("//CheckBoxBox");
nw:cbs << Set Function(function({this},					
	cb_idx = Contains(cbs, this);
	cb_zeroidx = cb_idx - 1; // easier to handle as 0-based
	
	cb_col = Mod(cb_zeroidx, window:colcount * 2) + 1; // + 1 to back to 1-based
	cb_row = Floor(cb_zeroidx / (window:colcount * 2)) + 1; // + 1 to back to 1-based
	cb_type = If(Mod(cb_col, 2), "Grp", "Ctrl");
	
	show(cb_idx, cb_col, cb_row, window:lvals[cb_row], cb_type);
	Write("\!N");
));

Write();
-Jarmo

View solution in original post

5 REPLIES 5
jthi
Super User

Re: Incorrect alignment of checkboxes on the user interface

I think easiest options might be to build your UI with H List Boxes instead of V List Box or by using Table Box / Lineup box.

 

With H List Box you can use Align("center"), with Table Box they should be aligned and same with Lineup Box. With Lineup Box you might want to use Lineup Ruler Box to modify the widths of each column

Names Default To Here(1);

strGroupColName = "Group";
lstGroupId = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"};

nw = New Window("",
	Lineup Ruler Box(
		Widths({50, 25,30,25,30,25,30,25,30,25,30,25,30}),
		lub = Lineup Box(N Col(11),
			Text Box("Group"),
			Text Box("Grp"),
			Text Box("Ctrl"),
			Text Box("Grp"),
			Text Box("Ctrl"),
			Text Box("Grp"),
			Text Box("Ctrl"),
			Text Box("Grp"),
			Text Box("Ctrl"),
			Text Box("Grp"),
			Text Box("Ctrl")
		);
	);
);

For Each({groupid}, lstGroupId,
	lub << Append(Text Box(groupid));
	For(i = 1, i <= 10, i++,
		lub << Append(Check Box(""))
	);
);

 

-Jarmo
EvaCo
Level II

Re: Incorrect alignment of checkboxes on the user interface

Hello, thank you for your feedback. Indeed, I have already considered using this "inline" structure, and I have reused your code to integrate the add and remove buttons.

strGroupColName = "Group";
lstGroupId = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"};
Ncol = 11;

// Function to generate widths
GenerateWidths = Function({n},
    widths = {50};
    For(i = 2, i <= n, i++,
        Insert Into(widths, 25);
    );
    Return(widths);
);

// Function to recreate the Lineup Box
RecreateLineupBox = Function({},
    lineupBox = Lineup Box(N Col(Ncol));
    lineupBox << Append(Text Box("Group"));
    For(j = 1, j <= (Ncol - 1) / 2, j++,
        lineupBox << Append(Text Box("Grp"));
        lineupBox << Append(Text Box("Ctrl"));
    );
    For Each({groupid}, lstGroupId,
        lineupBox << Append(Text Box(groupid));
        For(i = 1, i <= Ncol - 1, i++,
            lineupBox << Append(Check Box(""));
        );
    );
    Return(lineupBox);
);

// Function to update the main container with new contents
UpdateContainer = Function({container},
    lineupBox << Delete; // Delete the existing Lineup Box
    lub = RecreateLineupBox();
    container << Append(
        Lineup Ruler Box(
            Widths(GenerateWidths(Ncol)), // Adjust widths based on new Ncol
            lub
        )
    );
);

// Function to add a pair of Group and Control columns with checkboxes
AddGroupControlPair = Function({},
    Ncol = Ncol + 2;
    UpdateContainer(mainContainer);
);

// Function to remove the last pair of Group and Control columns with checkboxes
RemoveGroupControlPair = Function({},
    If(Ncol > 11,
        Ncol = Ncol - 2;
        UpdateContainer(mainContainer);
    );
);

// Initial window creation
nw = New Window("",
    mainContainer = V List Box(
        // Add and Remove Buttons
        H List Box(
            Button Box("Add", AddGroupControlPair),
            Button Box("Remove", RemoveGroupControlPair)
        ),
        lineupBox = Lineup Ruler Box(
            Widths(GenerateWidths(Ncol)),
            lub = RecreateLineupBox()
        )
    )
);

The drawback of this structure is that I find it difficult to imagine how to retrieve the content of my checkboxes "by column" as I used to do with lstcomparedpbx.

Jasean
Staff

Re: Incorrect alignment of checkboxes on the user interface

These lines will provide you with a matrix of 1's and 0's to indicate the status of each check box in your array layout based on position.  Does this get you what you need?  To check, run your latest script, make some selections as desired, then run these two lines.

cBoxes = nw << XPath("//CheckBoxBox");
results = Shape(Matrix(cBoxes << Get), NItems(cBoxes)/(NCol-1));
Show(results);

Jasean_0-1720641963079.png => Jasean_1-1720641993370.png

 

 

jthi
Super User

Re: Incorrect alignment of checkboxes on the user interface

Like @Jasean already suggested, you can use XPath to get references to all of the CheckBoxBoxes and then send << Get to that. You can then handle that in many different ways, below is other option

Names Default To Here(1);

strGroupColName = "Group";
lstGroupId = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"};
colcount = 5;

nw = New Window("CheckBox UI",
	window:lvals = lstGroupId;
	window:colcount = colcount;
	window:cbs = {};
	Lineup Ruler Box(
		Widths({50,40,45,40,45,40,45,40,45,40,45}),
		lub = Lineup Box(N Col(11));
	);
);

// Add "Headers"
lub << Append(Text Box("Group"));
For(i = 1, i <= colcount, i++,
	lub << Append(Text Box(Eval Insert("Grp(^i^)")));
	lub << Append(Text Box(Eval Insert("Ctrl(^i^)")));
);

// Add "Rows"
For Each({groupid, idx}, lstGroupId,
	lub << Append(Text Box(Eval Insert("^groupid^(^idx^)")));
	For(i = 1, i <= colcount * 2, i++,
		lub << Append(cb = Check Box(""));
	);	
);


// Add functions to check boxes
nw:cbs = nw << XPath("//CheckBoxBox");
nw:cbs << Set Function(function({this},					
	cb_idx = Contains(cbs, this);
	cb_zeroidx = cb_idx - 1; // easier to handle as 0-based
	
	cb_col = Mod(cb_zeroidx, window:colcount * 2) + 1; // + 1 to back to 1-based
	cb_row = Floor(cb_zeroidx / (window:colcount * 2)) + 1; // + 1 to back to 1-based
	cb_type = If(Mod(cb_col, 2), "Grp", "Ctrl");
	
	show(cb_idx, cb_col, cb_row, window:lvals[cb_row], cb_type);
	Write("\!N");
));

Write();
-Jarmo
EvaCo
Level II

Re: Incorrect alignment of checkboxes on the user interface

Hello,

Thank you both very much for your responses. They helped me a lot and allowed me to solve my problem.
Thank you very much. Have a great day.