Помните, где щелкнула мышь? ArrayLists? HashCodes?

Извините, ребята, я удалил свой пример APPLES и CATS:) Вот обновленная версия моего вопроса!

Я теряю рассудок здесь. Мне нужен кто-то, кто может просветить меня. Я несколько раз пытался объяснить мою проблему. Надеюсь, на этот раз мой вопрос будет легче понять.

В основном у меня есть этот фрейм, и там отображается изображение. Справа есть JList, а внизу внизу есть еще одна панель для JLabels. Вот скринкап моей рамки.

enter image description here

Когда я нажимаю на изображение, появляется JOptionPane, например. И я ввожу свой вклад. Мой JList - это ArrayList, поэтому все, что я вводил, добавляется в JList и JPanel внизу.

enter image description here

Теперь, когда я нахожусь на той части, где я нажал, вы заметили, что квадрат исчез). Он появляется только тогда, когда я нажимаю изображение, и когда я наводил метку внизу. Мои метки, на данный момент - LOLZ NOSE и INPUT HERE.

enter image description here

То, что я хочу сделать, - это когда я наводил курсор на ярлыке, например, INPUT HERE, он снова показывает квадрат, показывая часть, на которую я нажал. Моя проблема теперь, когда я нажимаю на NOSE, который должен показывать квадрат на носовой части и имя NOSE с черным bg, это НЕ ПОКАЗАТЬ. Кроме того, отображается только последний квадрат ярлыка, не обращая внимания на позицию остальных меток.

Как мне получить ярлык, чтобы запомнить позицию щелчка, который я делаю? Люди сказали, что я должен использовать ArrayLists или HashCodes, но я не знаю, как их реализовать. Спасибо всем, кто может помочь.

Изменить: я уже сделал прямоугольник, кстати. Он отображается только для ввода последней метки. Вот некоторые из запрошенных фрагментов кода.

Как я устанавливаю текст в JLabel и обновляю 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);

    }

Мой указатель мыши при нажатии:

@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);
        }
    }

Моя мышьСледующая панель при зависании:

@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();
    }

Как я рисую:

    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);
                }
            }
        }

Если вы хотите, чтобы я добавил еще несколько фрагментов, просто скажите мне!:)

Ответ 1

Вы должны создать HashMap, скажем что-то вроде:

Карта linkSet = new HashMap();

И всякий раз, когда вы нажимаете на чертеж и создаете метку, добавьте JLabel и точку на изображении в набор, используя метод put с JLabel в качестве ключа и Point в качестве значения. Затем в JLabel MouseMotionListener используйте метку в качестве ключа и получите соответствующую точку из набора, используя метод map get(...).

изменить
Исправлено в соответствии с комментарием alicedimarco. Еще раз спасибо!

изменить 2
Я думаю, вы хотите снова использовать карту. Если у вас есть карта, вы можете получить ее интересующую точку из JLabel или JList String, а затем передать эту точку классу, который рисует изображение, и пусть он использует Point для рисования прямоугольника. Например, вы можете дать классу рисования изображения поле Point, называемое displayPoint, и метод, называемый setDisplayPoint (точка p). Это может быть так просто:

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

и полагая, что объект интереса сосредоточен в этой точке, используйте displayPoint в методе paintComponent:

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);
  }
}

изменить 3:
Чтобы получить щелчки мыши, это довольно просто, просто добавьте MouseListener к компоненту, который содержит изображение:

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

И в вашем коде, который вызывается из этого прослушивателя мыши, используйте JOptionPane, чтобы получить выбор пользователя из имени тега, и добавьте результирующую строку в список listDataModel, чтобы он отображался в JList, а также в stringPointMap вместе с точкой, полученной из MouseEvent, чтобы вы могли сопоставить String с точкой и получить ее:

// !! 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);
  }
}

Что это.

Затем все вместе:

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 = "http://i.stack.imgur.com/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);
   }
}

Ответ 2

Одна приятная особенность JList заключается в том, что вы можете рассказывать о любом объекте в нем. Вы не ограничены строками. Когда объекты хранятся в JLists, swing вызовет метод toString() и отобразит его в списке.

Зная это, теперь вы можете написать свой собственный класс, в котором хранятся имя метки выбора и координаты поля. Этот объект toString() будет возвращать имя метки, что сделает правильную вещь в JList.

Затем в обработчике событий выбора для JList вы можете получить свой собственный объект и получить сохраненные в нем координаты ящика и нарисовать их на экране. Не нужно суетиться с другими контейнерами (хотя знать, как их использовать, это хорошо).

Хорошо, создайте класс, подобный этому...

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()
}

Класс выше переопределяет toString(), поэтому, когда вы помещаете его в JList, он будет использовать вызов toString(), чтобы определить, что отображать, и поскольку эта реализация toString возвращает имя метки, вы увидите, что в список.

И добавьте их в свой JList вместо строк. Затем в какой-то момент вашего кода вы сделаете что-то вроде этого...

// 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...

Надеюсь, что это поможет.