Subscribe Bookmark RSS Feed

MouseBox Selecting Multiple Images

msharp

Super User

Joined:

Jul 28, 2015

I want to select multiple images using a mousebox.

Below is an example that I've scripted showing how one can select an image one at a time.  But since there could be potentially hundreds of pictures, I want my user to be able to select multiple images with a drag function instead of having to click each one.  Any tips?

Names Default to here(1);

//dtFull contains image path information

dtFull = current data table();

path1 = dtFull:LocalPath[20];

path2 = dtFull:LocalPath[21];

path3 = dtFull:LocalPath[22];

path4 = dtFull:LocalPath[23];

img = NewImage(path1);

img2 = NewImage(path2);

img3 = NewImage(path3);

img4 = NewImage(path4);

selected= [0,0,0,0];

new window("test", Hlistbox(vlb = vlistbox(

       mb = mousebox(pb = Picture Box(img),

              << SetClickEnable(1),

              << SetClick( Function({this, clickpt, event},

                           If( event == "Pressed",

                                  selected[1] = !selected[1];

                                  If( selected[1],

                                         pb << Select,

                                         pb << Deselect

                                  )

                           );

                     );

              ),

       ),

       mousebox(pb2 = Picture Box(img2),

              << SetClickEnable(1),

              << SetClick( Function({this, clickpt, event},

                           If( event == "Pressed",

                                  selected[2] = !selected[2];

                                  If( selected[2],

                                         pb2 << Select,

                                         pb2 << Deselect

                                  );

                                 

                           );

                     );

              ),

       )),

       Vlistbox(

       mousebox(pb3 = Picture Box(img3),

              << SetClickEnable(1),

              << SetClick( Function({this, clickpt, event},

                     If( event == "Pressed",

                           selected[3] = !selected[3];

                           If( selected[3],

                                  pb3 << Select,

                                  pb3 << Deselect

                           )

                     ));

              )

       ),

       mousebox(pb4 = Picture Box(img4),

              << SetClickEnable(1),

              << SetClick( Function({this, clickpt, event},

                     If( event == "Pressed",

                           selected[4] = !selected[4];

                           If( selected[4],

                                  pb4 << Select,

                                  pb4 << Deselect

                           )

                     ));

              )

       ))

));

1 ACCEPTED SOLUTION

Accepted Solutions
Solution

11358_pastedImage_2.png


You might need to turn off the page translate feature at the top of the page before grabbing this code.  The magic is in the last few lines; everything else is setup.  At the end, <<getChildBox(location) is being used in a loop for a grid of pixels (every 10 pixels X and Y) within the range selected by mouse down to the current mouse location.  getChildBox returns 1, 2, or 3 boxes in this example, depending if the pixel is in a bitmap (3rd box) or just in a border (2nd box), or just in the lineup child of the mousebox (1st box).  If a second box is found, make it have a red background.  Also notice the loop just before that that clears all the boxes to white.  This code runs on both mouse moves and a timer tick; the "button" argument tells why the function is called.  Pressed is the mouse-down location.  lb[borderbox(1)]<<getbackgroundcolor will tell you if a box is red or white when the Release event happens.  You could add a text label too.  Note the border left...bottom values are set based on the picture size to center the picture.  That will need some adjusting if text is added.


If you need more control, the graphbox with picture segments and mousetrap might be an alternative.




New Window( "selection test", mb = MouseBox( lb = Lineup Box( N Col( 10 ) ) ) );

// generate some pictures of various sizes

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

  rows = Random Uniform( 10, 100 );

  cols = Random Uniform( 10, 100 );

  ls = (120 - cols) / 2;

  rs = 120 - cols - ls;

  ts = (120 - rows) / 2;

  bs = 120 - rows - ts;

  red = J( rows, cols, Random Uniform( 0, 1 ) );

  green = J( rows, cols, Random Uniform( 0, 1 ) );

  blue = J( rows, cols, Random Uniform( 0, 1 ) );

  lb << append( Border Box( sides( 15 ), Left( ls ), Right( rs ), top( ts ), bottom( bs ),

  New Image( "rgb", {red, green, blue} ) ) );

);

mb << setclickenable( 1 );

mb << setclick(

  Function( {this, coords, button},

  if( button == "Pressed",

  {pressedX,pressedY} = coords;

  ,

  {thisX,thisY} = coords;

  xstart=min(thisX,pressedX)-5;

  xstop=max(thisX,pressedX)+5;

  xstep=10;

  ystart=min(thisY,pressedY)-5;

  ystop=max(thisY,pressedY)+5;

  ystep=10;

  // turn off all previous selections

  for( b=lb<<child, !isEmpty(b), b=b<<sib, b<<setbackgroundcolor("white") );

  // test points in the selection box

  for(x=xstart, x<=xstop, x+=xstep,

  for(y=ystart, y<=ystop, y+=ystep,

  boxes = mb << getchildbox( {x,y} );

  If( N Items( boxes ) >= 2,

  boxes[2] << setbackgroundcolor( "red" )

  );

  );

  );

  );

  )

);

Craige
3 REPLIES
Solution

11358_pastedImage_2.png


You might need to turn off the page translate feature at the top of the page before grabbing this code.  The magic is in the last few lines; everything else is setup.  At the end, <<getChildBox(location) is being used in a loop for a grid of pixels (every 10 pixels X and Y) within the range selected by mouse down to the current mouse location.  getChildBox returns 1, 2, or 3 boxes in this example, depending if the pixel is in a bitmap (3rd box) or just in a border (2nd box), or just in the lineup child of the mousebox (1st box).  If a second box is found, make it have a red background.  Also notice the loop just before that that clears all the boxes to white.  This code runs on both mouse moves and a timer tick; the "button" argument tells why the function is called.  Pressed is the mouse-down location.  lb[borderbox(1)]<<getbackgroundcolor will tell you if a box is red or white when the Release event happens.  You could add a text label too.  Note the border left...bottom values are set based on the picture size to center the picture.  That will need some adjusting if text is added.


If you need more control, the graphbox with picture segments and mousetrap might be an alternative.




New Window( "selection test", mb = MouseBox( lb = Lineup Box( N Col( 10 ) ) ) );

// generate some pictures of various sizes

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

  rows = Random Uniform( 10, 100 );

  cols = Random Uniform( 10, 100 );

  ls = (120 - cols) / 2;

  rs = 120 - cols - ls;

  ts = (120 - rows) / 2;

  bs = 120 - rows - ts;

  red = J( rows, cols, Random Uniform( 0, 1 ) );

  green = J( rows, cols, Random Uniform( 0, 1 ) );

  blue = J( rows, cols, Random Uniform( 0, 1 ) );

  lb << append( Border Box( sides( 15 ), Left( ls ), Right( rs ), top( ts ), bottom( bs ),

  New Image( "rgb", {red, green, blue} ) ) );

);

mb << setclickenable( 1 );

mb << setclick(

  Function( {this, coords, button},

  if( button == "Pressed",

  {pressedX,pressedY} = coords;

  ,

  {thisX,thisY} = coords;

  xstart=min(thisX,pressedX)-5;

  xstop=max(thisX,pressedX)+5;

  xstep=10;

  ystart=min(thisY,pressedY)-5;

  ystop=max(thisY,pressedY)+5;

  ystep=10;

  // turn off all previous selections

  for( b=lb<<child, !isEmpty(b), b=b<<sib, b<<setbackgroundcolor("white") );

  // test points in the selection box

  for(x=xstart, x<=xstop, x+=xstep,

  for(y=ystart, y<=ystop, y+=ystep,

  boxes = mb << getchildbox( {x,y} );

  If( N Items( boxes ) >= 2,

  boxes[2] << setbackgroundcolor( "red" )

  );

  );

  );

  );

  )

);

Craige
msharp

Super User

Joined:

Jul 28, 2015

Thanks a ton for setting me on the right path.

I changed the code a bit so the user can choose to select or unselect, instead of automatically unselecting everything.

So i guess the next problem, comes with tracking the selection.  See the below code, it seems to work, but it just feels awkward to me.

mb << setclick(

  Function( {this, coords, button},

  if( button == "Pressed",

  {pressedX,pressedY} = coords;

  try(pressedBox = mb << getchildbox( {pressedX,pressedY} );

  pressedBoxColor = pressedBox[2] << GetBackgroundColor);

  ,

  {thisX,thisY} = coords;

  xstart=min(thisX,pressedX)-5;

  xstop=max(thisX,pressedX)+5;

  xstep=10;

  ystart=min(thisY,pressedY)-5;

  ystop=max(thisY,pressedY)+5;

  ystep=10;

  // turn off all previous selections

  //for( b=lb<<child, !isEmpty(b), b=b<<sib, b<<setbackgroundcolor("white") );

  // test points in the selection box

  for(x=xstart, x<=xstop, x+=xstep,

  for(y=ystart, y<=ystop, y+=ystep,

  boxes = mb << getchildbox( {x,y} );

  If( N Items( boxes ) >= 2,

  if(pressedBoxColor == "Red",

  boxes[2] << setbackgroundcolor( "white" )

  , boxes[2] << setbackgroundcolor( "red" ))

  );

  );

  );

  );

  )

);

selection = J(1, 200, 0);

counter=0;

for( b=lb<<child, !isEmpty(b), b=b<<sib,

  counter++;

  if((b<<getbackgroundcolor) == "Red",

  selection[counter] = 1

  );

);

Craige_Hales

Staff

Joined:

Mar 21, 2013

you could also use the JSL functions isShiftKey, isAltKey, isControlKey to manage the red/white decision.  The loop to gather the selection could be run on the button release.  I think it is "Release", print out the button variable to check...away from desk...

Craige