Subscribe Bookmark RSS Feed

Appending objects horizontally

Hi,

I've written myself a little image viewer to enable me to browse a folder of digital photographs from within JMP 9, and include the script below.  The problem I have is that I want to retain the relative positions of the List Box and the Graph Box in which the images are being shown while the tool is being used.  At the moment, when I select an image from the list to replace the initial one, the new Graph Box is appended underneath the list, whereas I want it to appear in the same position that I originally put it - to the right of the list.  I know why it's doing it: the "<< append" property attaches the new chart vertically.  The question is, how can I modify the script to append it horizontally?

// Start of program;

Clear Log();

PhotoFolder = "C:\My Photos\Camera Card 1\102_FUJI\";

ImageList = Files In Directory( PhotoFolder ); // Every file is a JPEG, so no need to filter them;

Expr_Create_Image = Expr(

       ImageName = PhotoFolder || ImageList[ImageNumber];

       gb = Graph Box(

              Frame Size( 410, 308 ),

              X Scale( 0, 100 ),

              Y Scale( 0, 100 ),

              <<background color( {0.7, 0.7, 0.7} ),

              <<Add Image( Open( ImageName ), Bounds( Left( 5 ), Right( 95 ), Top( 95 ), Bottom( 5 ) ) )

       );

        // I don't want to see the axes, so get rid of them;

       gb[axisbox( 2 )] << delete;

       gb[axisbox( 1 )] << delete;

);

Expr_Replace_Chart = Expr(

       nw[OwnerBox( 1 )] << delete; // Delete the old one from the window;

       nw << append( gb ); // Append the new one;

);

      

lb = List Box(

       ImageList,

       ImageNumber = (lb << get selected indices)[1];

       Eval( Expr_Create_Image ); // Create a new graph box;

       Eval( Expr_Replace_Chart ); // Substitute the new graph for the old one;

,

       max selected( 1 )

);

ImageNumber = 1; // Initially show the first one;

Eval( Expr_Create_Image ); // Create the chart;

lb << set selected( ImageNumber, 1 ); // Pre-select the first element of the list;

nw = New Window( "New Window", H List Box( lb, gb ) ); // And display the window;

// End of program;

More generally, is there a way simply to replace the original chart with the new one in such a way that it isn't necessary to partially deconstruct and then reconstruct the display window, the way I'm doing it at the moment?  The obvious solution would be simply to replace the initial image within the Graph Box with the new one selected from the List Box, but I can't seem to do that: using the "<< add image" property on the same Graph Box a second time doesn't seem to work – which is why at the moment I’m creating a new Graph Box every time.

Many thanks for any suggestions.

1 ACCEPTED SOLUTION

Accepted Solutions
Solution

This was fun. With risk of making your app bloatware I also post a version with buttons for rotating and zooming the current image. Alt key reverses the function.

ImageList = Files In Directory( PhotoFolder = Pick Directory() );

ImageNumber = 1;

Expr_pb = Expr( pb = Panel Box( , Picture Box( img ) ) );

Expr_Create_Image = Expr(

          ImageName = PhotoFolder || ImageList[ImageNumber];

          img = Open( ImageName, jpg );

          img_size = img << getsize;

          If( img_size[1] > img_size[2],

                    img << set size( {410, 308} ),

                    img << set size( {308, 410} )

          );

          Expr_pb;

);

Expr_replace_image = Expr(

          nw[Panel Box( 1 )] << delete;

          hlb << append( pb );

);

rotate = Button Box( "Rotate",

  If( Is Alt Key(),

                    img << rotate( -90 ),

                    img << rotate( 90 )

          );

          Expr_pb;

          Expr_replace_image;

);

zoom = Button Box( "Zoom",

  If( Is Alt Key(),

                    img << set size( Eval List( {(img << get size)[1] / 1.5, (img << get size)[2] / 1.5} ) ),

                    img << set size( Eval List( {(img << get size)[1] * 1.5, (img << get size)[2] * 1.5} ) )

          );

          Expr_pb;

          Expr_replace_image;

);

rotate << set tip( "Rotate 90° right, hold alt key to rotate 90° left" );

zoom << Set Tip( "press to increase size, hold alt key to decrease" );

lb = List Box(

          ImageList,

          ImageNumber = (lb << get selected indices)[1];

          Expr_Create_Image;

          Expr_replace_image;,

          max selected( 1 )

);

Expr_Create_Image;

nw = New Window( "test", hlb = H List Box( V List Box( lb, rotate, zoom ), pb ) );

6 REPLIES
ms

Super User

Joined:

Jun 23, 2011

Nice little application! I have not looked into the generalization of the problem (modify instead of replace gb) but I made a little change that seem to retain the horizontal layout. In the script below I just show the lines that have been changed.

...

Expr_Replace_Chart = Expr(

       nw[OwnerBox( 1 )] << delete; // Delete the old one from the window;

       hlb << append( gb ); // Append the new one to the H List Box

);

...

try(Eval( Expr_Create_Image )); // Create the chart; // I enclosed this into try to avoid error message first time

...

nw = New Window( "New Window", hlb=H List Box( lb, gb ) ); // And display the window; Give the H List Box a reference

...

Excellent - many thanks!  (Actually, something that would make it more useful generally would be some means of determining the dimensions of each image when it is loaded: if I could do that, I could then create each chart with the correct aspect ratio every time, as opposed to having all the photos that were taken in portrait mode squashed into landscape format, as they are at the moment.  I can't see a way to do that offhand, but that doesn't mean it isn't possible.  If anyone happens to know how to do that, could you show me how?)

Once again, many thanks,

David

ms

Super User

Joined:

Jun 23, 2011

Here is an example (modification of your original idea) that use image<<get size to find the aspect ratio. I have skipped the graphbox and used a panelbox instead, so the window looks slightly different. Otherwise the function should be similar to the original.

ImageList = Files In Directory( PhotoFolder = Pick Directory() );

ImageNumber = 1;

Expr_Create_Image = Expr(

          ImageName = PhotoFolder || ImageList[ImageNumber];

          img = Open( ImageName, jpg );

          img_size = img << getsize;

          If( img_size[1] > img_size[2],

                    img << set size( {410, 308} ),

                    img << set size( {308, 410} )

          );

          pb = Picture Box( img );

          bb = Panel Box( , pb );

);

Expr_replace_image = Expr(

          nw[Panel Box( 1 )] << delete;

          hlb << append( bb );

);

lb = List Box(

          ImageList,

          ImageNumber = (lb << get selected indices)[1];

          Eval( Expr_Create_Image );

          Eval( Expr_replace_image );,

          max selected( 1 )

);

Eval( Expr_Create_Image );

nw = New Window( "test", hlb = H List Box( lb, bb ) );

Perfect - that's exactly what I needed, and also simplifies things into the bargain.  Many thanks!

Solution

This was fun. With risk of making your app bloatware I also post a version with buttons for rotating and zooming the current image. Alt key reverses the function.

ImageList = Files In Directory( PhotoFolder = Pick Directory() );

ImageNumber = 1;

Expr_pb = Expr( pb = Panel Box( , Picture Box( img ) ) );

Expr_Create_Image = Expr(

          ImageName = PhotoFolder || ImageList[ImageNumber];

          img = Open( ImageName, jpg );

          img_size = img << getsize;

          If( img_size[1] > img_size[2],

                    img << set size( {410, 308} ),

                    img << set size( {308, 410} )

          );

          Expr_pb;

);

Expr_replace_image = Expr(

          nw[Panel Box( 1 )] << delete;

          hlb << append( pb );

);

rotate = Button Box( "Rotate",

  If( Is Alt Key(),

                    img << rotate( -90 ),

                    img << rotate( 90 )

          );

          Expr_pb;

          Expr_replace_image;

);

zoom = Button Box( "Zoom",

  If( Is Alt Key(),

                    img << set size( Eval List( {(img << get size)[1] / 1.5, (img << get size)[2] / 1.5} ) ),

                    img << set size( Eval List( {(img << get size)[1] * 1.5, (img << get size)[2] * 1.5} ) )

          );

          Expr_pb;

          Expr_replace_image;

);

rotate << set tip( "Rotate 90° right, hold alt key to rotate 90° left" );

zoom << Set Tip( "press to increase size, hold alt key to decrease" );

lb = List Box(

          ImageList,

          ImageNumber = (lb << get selected indices)[1];

          Expr_Create_Image;

          Expr_replace_image;,

          max selected( 1 )

);

Expr_Create_Image;

nw = New Window( "test", hlb = H List Box( V List Box( lb, rotate, zoom ), pb ) );

This is great: I've just incorporated the above into an application I'm working on at the moment for use as a general-purpose graphics file browser: the only change I'll probably make is to generalise that (410-by-308) aspect ratio to reflect any supplied input dimensions, as the images I'm looking at potentially include exported output from JMP graph boxes which could in principle be any size.  Why not submit a copy of the above to the File Exchange?  There are practical examples here in the use of Picture Boxes, swapping components in an output window and usage of the <Alt> key, and it's not hard to imagine any number of potential uses.

Once again, many thanks!