0
votes

Currently, there is a disconnect between where I click and the coordinates that are printed to terminal. It seems it is basing the coordinates off of the center GridPane but not the image itself of the imageView.

Previously, I would not resize the images in this application but rather in an automated photoshop process and the click/coordinates would be in sync.

Here is where I make an arrayList of resized Images which will be displayed in the GridPane

//Makes imageView arraylist from all images in a given directory
   private ArrayList<ImageView> makeImageViewArr(File imagesDir) { 

      //transer file names from directory folder to string array
      File[] strImageList = imagesDir.listFiles();
      myMouseHandler mouseHandler = new myMouseHandler();

      //instantiate imageview arraylist
      arrImageList = new ArrayList<ImageView>();

      //get files from folder & start at 1 to ignore ds.Store
      for(int count = 1; count < strImageList.length; count++) {
         ImageView imgView = 
         new ImageView(strImageList[count].toURI().toString());

         imgView.setFitHeight(360);
         imgView.setFitWidth(640);
         imgView.setPreserveRatio(true);
         imgView.setSmooth(true);
         imgView.setOnMouseClicked(mouseHandler);
         arrImageList.add(imgView);
      }

      return arrImageList;
   }//END METHOD

Here is the class where I handle the actual click on the imageView

//inner class for mouse input
   public class myMouseHandler implements EventHandler<MouseEvent>
   {
      /* Method which handles & executes mouse clicks 
       *
       * @param e KeyEvent the code from the mouse click
       *
       * returns none
       */
      @Override
         public void handle(MouseEvent e)
         {  
            //reset image to erase previous box
            pane.setCenter(arrImageList.get(index));

            //get image that was clicked on and pixel reader from image
            Image clickedImg = arrImageList.get(index).getImage();
            PixelReader pxlRdr = clickedImg.getPixelReader();

            //get image height/width for copy 
            int clickedImgW = (int) clickedImg.getWidth(); 
            int clickedImgH = (int) clickedImg.getHeight(); 

            //get x and y coordinates from click
            int xCord = (int) e.getX();
            int yCord = (int) e.getY();

            nudgeX = xCord;
            nudgeY = yCord;

            //create writeable image and pixelwriter to draw click region
            WritableImage outlineImg = new WritableImage(pxlRdr, 
                  clickedImgW, clickedImgH);
            PixelWriter pxlWrtr;
            pxlWrtr = outlineImg.getPixelWriter();

            //draws region 
            drawRegion(pxlWrtr, xCord, yCord);

            //display image with click boundary and link mouseHandler
            //to refresh on next click
            ImageView tempImg = new ImageView(outlineImg);
            tempImg.setFitHeight(360);
            tempImg.setFitWidth(640);
            tempImg.setPreserveRatio(true);
            tempImg.setSmooth(true);
            myMouseHandler mouseHandler = new myMouseHandler();
            tempImg.setOnMouseClicked( mouseHandler );
            pane.setCenter( tempImg );

            //print relevant info about click region        
            System.out.println("xCord: " + xCord);
            System.out.println("yCord: " + yCord + "\n");            
         }//END METHOD
   }//END INNER CLASS

This simply draws a region to show where the click has occurred.

//Draws region boundary after user clicks on image
   private void drawRegion(PixelWriter pxlWrtr, int xCord, int yCord) {

      Image clickedImg = arrImageList.get(index).getImage();
      PixelReader pxlRdr = clickedImg.getPixelReader();

      //get image height/width for copy 
      int clickedImgW = (int) clickedImg.getWidth(); 
      int clickedImgH = (int) clickedImg.getHeight();

      //draw right vert boundary
      for( int yTrack = (yCord + 1); yTrack > (yCord - regionSize ); yTrack--) {
         if((yTrack > 0 && yCord < clickedImgH - 1)  
               && ( xCord < clickedImgW - 1 )) {
            pxlWrtr.setColor(xCord + 1, yTrack, Color.RED);
         }
      }

      //draw left vert boundary
      for( int yTrack = (yCord + 1); yTrack > (yCord - regionSize); yTrack--) {
         if((yTrack > 0 && yCord < clickedImgH - 1) 
               && (xCord - regionSize) >= 0) {
            pxlWrtr.setColor(xCord - regionSize, yTrack, Color.RED);
         }
      }

      //draw bottom boundary
      for(int xTrack = (xCord + 1); xTrack >= (xCord - regionSize); xTrack--) {
         if(xTrack > 0 && yCord < clickedImgH - 1) {
            pxlWrtr.setColor(xTrack, yCord + 1, Color.RED);
         }
      }

      //draw top boundary
      for(int xTrack = (xCord + 1); xTrack >= (xCord - regionSize); xTrack--) {
         if(xTrack >= 0 && (yCord - regionSize) >= 0 ) {
            pxlWrtr.setColor(xTrack, yCord - regionSize, Color.RED);
         }
      }
   }//END METHOD
1
Are you expecting the MouseEvent coordinates to be coordinates in the scaled image? Mouse events are always based on screen pixels, and are never going to be scaled according to any image scaling. - VGR
Yes, that is quite a problem @VGR So how does one deal with clicking on scaled images? - David Owens

1 Answers

0
votes

According to the documentation for preserveRatio:

…the dimensions of this node as reported by the node's bounds will be equal to the size of the scaled image…

So you can use that to scale the MouseEvent coordinates:

double x = e.getX();
double y = e.getY();

ImageView view = (ImageView) e.getSource();
Bounds bounds = view.getLayoutBounds();
double xScale = bounds.getWidth() / view.getImage().getWidth();
double yScale = bounds.getHeight() / view.getImage().getHeight();

x /= xScale;
y /= yScale;

int xCord = (int) x;
int yCord = (int) y;