Remembering where a mouse clicked? ArrayLists? HashCodes?
Asked Answered
P

2

11

Sorry guys, I deleted my APPLES and CATS example :) Here's the updated version of my question!

I'm losing my sanity here. I need someone who can enlighten me. I've tried a couple of times explaining my problem here. Hopefully, this time, my question will be easier to understand.

Basically I have this frame, and there's an image displayed. There is a JList on the right, and there is another panel for JLabels at the bottom. Here's a screencap of my frame.

enter image description here

When I click on the image, a JOptionPane pops out, like so. And I enter my input. My JList is an ArrayList, so everything I input is added to the JList and the JPanel at the bottom.

enter image description here

Now, when I hover on the the part where I clicked, you noticed that the square disappeared). It only appears when I click the image, and when I hover the label at the bottom. My labels, as of now are LOLZ NOSE and INPUT HERE.

enter image description here

What I want to do is when I hover on the label, for example INPUT HERE, it shows the square again, featuring the part where I clicked. My problem now is when I click on NOSE, which is supposed to be showing a square on the nose part and a the name NOSE with black bg, IT IS NOT SHOWING. Also, only the last label's square is shown, disregarding the other labels' position clicked.

How do I get a label to remember the position of the click I make? People said I should use ArrayLists or HashCodes however I have no idea how to implement them. Thank you to anyone who can help.

Edit: I've already done the rectangle, btw. It's showing only for the last label inputted. Here are some of the code snippets requested!

How I'm setting the text on JLabel and updating the JList:

public void updateLabel(){

        StringBuilder text = new StringBuilder(); //creates empty builder, capacity 16

        for(Object s: tagModel.toArray()) //returns an array containing the elements of the tagModel
            text.append(" " + s);

        repaint();      
        hoverLabel.setText(text.toString()); //returns a String
        hoverLabel.addMouseMotionListener(this);
        hoverPanel.add(hoverLabel);

    }

My mouseListener upon click:

@Override
    public void mouseClicked(MouseEvent event) {
        // TODO Auto-generated method stub

        x = event.getX();
        y = event.getY();

        isRectPresent = true;
        repaint();

        input = JOptionPane.showInputDialog("Enter tag name:");

        if((input != null) && !input.isEmpty()){
            tagModel.addElement(input);
        }
    }

My mouseMotionListener upon hovering:

@Override
    public void mouseMoved(MouseEvent e) {
        // TODO Auto-generated method stub

        xpos = e.getX(); //gets where the mouse moved
        ypos = e.getY(); 

        //checks if the mouse is inside the bounds of the rectangle
        if (xpos > x && xpos < x + 100 && ypos > y && ypos < y + 100)
            isRectPresent = false;

        if(e.getSource() == hoverLabel){
            isRectPresent = true;
            repaint();
        }

        repaint();
    }

How I'm painting:

    public void paintComponent(Graphics g){ 
            Graphics2D g2 = (Graphics2D) g;

            g2.drawImage(image, 0, 0, null);

            if(image != null && isRectPresent){                 
                            Stroke stroke = g2.getStroke();
                g2.setStroke(new BasicStroke(4));
                g2.setColor(Color.WHITE);
                g2.drawRect(x-50, y-50, 100, 100);
                g2.setStroke(stroke);
            }else{
                if(xpos > x && xpos < x + 100 && ypos > y && ypos < y + 100){
                    g.setColor(Color.BLACK);
                    g.fillRect(x-50, y-50, 100, 25);
                    g.setColor(Color.WHITE);
                    g.setFont(new Font("Tahoma", Font.BOLD, 12));
                    g.drawString(input, x-30, y-30);
                }
            }
        }

If you want me to add some more snippets, just tell me! :)

Powys answered 30/11, 2011 at 18:12 Comment(10)
+1 For juxtaposing "Apples" and "Cats"Cobble
i would say to work on your acceptance rating and maybe post some code of your mousemotionlistenerInterpolate
" it should detect the point, and a rectangle will show up on that area where I clicked." -- but you didn't click a rectangle but rather a point. Would this be an certain sized rectangle of fixed size centered on the point? If so, how big the size? Also, the label area on the button could in fact be a JList.Puppis
Oh yeah, about that... a rectangle still appears when I click the image to ensure that the mouseListener for the input pane is activated. Then for the code of the rectangle, I have this: g2.drawRect(x-50, y-50, 100, 100);Powys
@alicedimarco: see update in answer.Puppis
@HovercraftFullOfEels Thanks, I'm gonna go over your code :)Powys
Wow, your work is flawless. However, the points are already initialized. I'm wondering if it's possible that when the user clicks, it saves the x and y coordinate to Point? If so, how?Powys
Just use a MouseListener for that.Puppis
I finished it, but for some reason, when I merge it with my current code, the image is not appearing on the screen. I'm getting my image via filechooser, btw, not by reading the URL.Powys
@taeyeon: the problem mentioned above is a completely separate problem not related to the current one. If you still haven't solved it, then you'll want to ask another question and provide all the necessary details. Luck!Puppis
P
3

You should create a HashMap, say something like:

Map linkSet = new HashMap();

And whenever you click on the drawing and create a label, add the JLabel and the point on the image to the set using the put method with the JLabel as the key and the Point as the value. Then in the JLabel's MouseMotionListener, use your label as a key and obtain the corresponding point from the set using the map's get(...) method.

edit:
Corrected as per alicedimarco's comment. Again, thanks!

edit 2
I think you want again to use a Map. If you have a Map, you can have it retrieve the Point of interest from the JLabel's or the JList's String, and then pass this Point to the class that's drawing the image and let it use the Point to draw a rectangle. For instance you could give the image drawing class a Point field called displayPoint, and a method called setDisplayPoint(Point p). It can be as simple as this:

public void setDisplayPoint(Point p) {
  this.displayPoint  = p;
  repaint();
}

and assuming that the object of interest is centered at that point, use the displayPoint in the paintComponent method:

protected void paintComponent(Graphics g) {
  super.paintComponent(g);
  // draw image
  if (img != null) {
     g.drawImage(img, X_SHIFT, Y_SHIFT, null);
  }

  // if displayPoint not null, draw the surrounding rectangle
  if (displayPoint != null) {
     g.setColor(RECT_COLOR);
     int x = displayPoint.x - RECT_WIDTH / 2;
     int y = displayPoint.y - RECT_WIDTH / 2;
     int width = RECT_WIDTH;
     int height = RECT_WIDTH;
     g.drawRect(x, y, width, height);
  }
}

edit 3:
To get mouse clicks, it's quite easy, simply add a MouseListener to the component that holds the image:

     // !! added
     imgRect.addMouseListener(new MouseAdapter() {
        public void mousePressed(MouseEvent e) {
           imgMousePressed(e);
        }
     }); 

And in your code that is called from this mouse listener, use a JOptionPane to get the user's choice of tag name, and add the resulting String to both the listDataModel so that it is seen in the JList and also in the stringPointMap together with the Point obtained from the MouseEvent so that you can map the String to the Point and be able to retrieve it:

// !! added
private void imgMousePressed(MouseEvent e) {
  String result = JOptionPane.showInputDialog(this,
        "Please enter name for this point on image:");
  if (result != null) {
     stringPointMap.put(result, e.getPoint());
     listDataModel.addElement(result);
  }
}

That's it.

Then putting it all together:

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import javax.imageio.ImageIO;
import javax.swing.*;

@SuppressWarnings("serial")
public class ImageRectMain extends JPanel {
   private ImageRect imgRect;
   private DefaultListModel listDataModel = new DefaultListModel();
   private JList list = new JList(listDataModel);
   private Map<String, Point> stringPointMap = new HashMap<String, Point>();

   public ImageRectMain() {
      String nose = "Nose";
      String ear = "Ear";
      String rightEye = "Right Eye";
      String leftEye = "Left Eye";
      listDataModel.addElement(ear);
      listDataModel.addElement(nose);
      listDataModel.addElement(rightEye);
      listDataModel.addElement(leftEye);
      stringPointMap.put(nose, new Point(480, 500));
      stringPointMap.put(ear, new Point(270, 230));
      stringPointMap.put(rightEye, new Point(380, 390));
      stringPointMap.put(leftEye, new Point(662, 440));

      MouseAdapter listMouseAdapter = new MouseAdapter() {
         @Override
         public void mouseMoved(MouseEvent e) {
            listMouseMoved(e);
         }

         @Override
         public void mouseExited(MouseEvent e) {
            listMouseExited(e);
         }

      };
      list.addMouseMotionListener(listMouseAdapter);
      list.addMouseListener(listMouseAdapter);

      try {
         imgRect = new ImageRect();

         // !! added
         imgRect.addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent e) {
               imgMousePressed(e);
            }
         }); 

         JPanel eastPanel = new JPanel();
         eastPanel.setLayout(new BoxLayout(eastPanel, BoxLayout.PAGE_AXIS));
         eastPanel.add(new JLabel("You have tagged the following:"));
         eastPanel.add(new JScrollPane(list));
         eastPanel.add(Box.createVerticalGlue());
         eastPanel.add(Box.createVerticalGlue());
         eastPanel.add(Box.createVerticalGlue());
         eastPanel.add(Box.createVerticalGlue());
         setLayout(new BorderLayout());
         add(imgRect, BorderLayout.CENTER);
         add(eastPanel, BorderLayout.EAST);
      } catch (MalformedURLException e) {
         e.printStackTrace();
      } catch (IOException e) {
         e.printStackTrace();
      }
   }

   // !! added
   private void imgMousePressed(MouseEvent e) {
      String result = JOptionPane.showInputDialog(this,
            "Please enter name for this point on image:");
      if (result != null) {
         stringPointMap.put(result, e.getPoint());
         listDataModel.addElement(result);
      }
   }

   private void listMouseExited(MouseEvent e) {
      imgRect.setDisplayPoint(null);
   }

   private void listMouseMoved(MouseEvent e) {
      int index = list.locationToIndex(e.getPoint());
      Object value = listDataModel.get(index);
      if (value != null) {
         Point point = stringPointMap.get(value.toString());
         if (point != null) {
            imgRect.setDisplayPoint(point);
         }
      }
   }

   private static void createAndShowGui() {
      JFrame frame = new JFrame("ImageRectMain");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(new ImageRectMain());
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

@SuppressWarnings("serial")
class ImageRect extends JPanel {
   public static final String IMAGE_PATH = "https://i.sstatic.net/7oNzg.jpg";
   private static final int DEFAULT_W = 687;
   private static final int DEFAULT_H = 636;
   private static final int X_SHIFT = -6;
   private static final int Y_SHIFT = -26;
   private static final Color RECT_COLOR = Color.pink;
   private static final int RECT_WIDTH = 40;
   private BufferedImage img;
   private Point displayPoint = null;

   public ImageRect() throws MalformedURLException, IOException {
      img = ImageIO.read(new URL(IMAGE_PATH));
   }

   public void setDisplayPoint(Point p) {
      this.displayPoint = p;
      repaint();
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      if (img != null) {
         g.drawImage(img, X_SHIFT, Y_SHIFT, null);
      }
      if (displayPoint != null) {
         g.setColor(RECT_COLOR);
         int x = displayPoint.x - RECT_WIDTH / 2;
         int y = displayPoint.y - RECT_WIDTH / 2;
         int width = RECT_WIDTH;
         int height = RECT_WIDTH;
         g.drawRect(x, y, width, height);
      }
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(DEFAULT_W, DEFAULT_H);
   }
}
Puppis answered 30/11, 2011 at 19:12 Comment(8)
Is this the same as a HashMap?Powys
@alicedimarco: no it's not the same, because I flubbed up --, you're right and I'm wrong -- it should be a HashSet. ... correcting my answer, and thanks!!!Puppis
Ohhh. Okay. lol. But I also searched this up and this works too! You're not wrong! I'm still having problems though :( but thanks~Powys
@alicedimarco: If still having problems, then either update your question with the specifics or start a new question.Puppis
@taeyeon: see edit 3 on how to listen for mouse clicks in the image-holding component.Puppis
I've actually been able to use some pieces of your code :) It helped me comprehend hash maps better. Thank you. This is what I needed after all. I have alternatives, but I understood this one better. My only problem now is I have to display the name inputted on each rectangle, but I think I got this one. Feel free to pitch in some ideas though. Thanks again!Powys
Thank you for helping me understand the concept of HashMaps :D I've solved my problems because of you. I reward you my 50 rep points~ Thanks so much!Powys
You're welcome and best of luck on your project. It looks to be a very interesting one.Puppis
C
3

One nice feature of a JList is that you can story any object in it. You're not limited to strings. When objects are stored in JLists, swing will call the object's toString() method, and display it in the list.

Knowing this, you can now write your own class that stores the name of your selection label and the coordinates of the box. This object's toString() method will return the name of the label, which will make the right thing appear in the JList.

Then, in the selection event handler for the JList, you can get your custom object out, and retrieve the box coordinates stored in it, and draw them on the screen. No need to fuss with other containers (although knowing how to use them is a good thing to).

Ok, Create a class like this...

public class MyLabel {
    private int x;
    private int y;
    private String text;

    public MyLabel (String text, int x, int y) {
        this.text = text;
        // assign x and y too...
    }

    @Override
    public String toString() {
        return label;
    }

    public int getX() {
        return x;
    }

    // similar function to getY()
}

The class above overrides toString(), so when you put it in a JList, it will use the call to toString() to determine what to display, and since this toString implementation returns the label name you'll see that in the list.

And add those into your JList instead of Strings. Then at some point in your code you'll do something like this...

// this is pseudocode, method names may not be correct...

MyLabel ml = (MyLabel)jList.getSelectedItem();
int x = ml.getX();
int y = ml.getY();
// draw the box...

Hope that helps.

Counterreply answered 2/12, 2011 at 0:34 Comment(10)
So you mean I don't have to make an array for the labels and coordinates?Powys
If you consolidate your labels and coordinates into the same object (make sure to override toString), then you can just store that object int the JList.Counterreply
I don't get it. Sorry, I'm just a java beginner :( your terms are a little bit hard for me to comprehend.Powys
Nothing wrong with being a beginner. ;-) I've added some example code.Counterreply
Thank you :) I'm glad you gave me a sample code. I'll go try this out and let you know!Powys
it's saying that I can't cast getSelectedIndex to Label D: and, getSelectedItem was causing a syntax error D: Also, how to I return my label when it's in the other class?Powys
Try checking the Javadoc for JList to figure out exactly what method to call to get the currently selected item.Counterreply
Hello~ I've tried your code once more and I'm getting a nullpointer exception on ml.getX and ml.getY D: hmmm and what do you mean by this: "And add those into your JList instead of Strings." ?Powys
That means getSelectedItem is returning null. You'll have to figure out the right time to call it.Counterreply
Thanks. I think I have it figured out now :DPowys

© 2022 - 2024 — McMap. All rights reserved.