还记得鼠标点击的地方吗?数组列表?哈希码?
Posted
技术标签:
【中文标题】还记得鼠标点击的地方吗?数组列表?哈希码?【英文标题】:Remembering where a mouse clicked? ArrayLists? HashCodes? 【发布时间】:2012-01-09 23:23:42 【问题描述】:抱歉,我删除了我的 APPLES 和 CATS 示例 :) 这是我的问题的更新版本!
我在这里失去理智了。我需要一个可以启发我的人。我已经尝试了几次在这里解释我的问题。希望这一次,我的问题会更容易理解。
基本上我有这个框架,并且显示了一个图像。右侧有一个 JList,底部有另一个 JLabels 面板。这是我的框架的屏幕截图。
当我单击图像时,会弹出一个 JOptionPane,就像这样。然后我输入我的输入。我的 JList 是一个 ArrayList,所以我输入的所有内容都会添加到 JList 和底部的 JPanel 中。
现在,当我将鼠标悬停在我单击的部分上时,您注意到正方形消失了)。它仅在我单击图像并将标签悬停在底部时出现。我的标签,目前是 LOLZ NOSE 和 INPUT HERE。
我想要做的是,当我将鼠标悬停在标签上时,例如 INPUT HERE,它会再次显示正方形,其中包含我单击的部分。我现在的问题是当我点击 NOSE 时,它应该在鼻子部分显示一个正方形和一个带有黑色 bg 的名称 NOSE,它没有显示。此外,只显示最后一个标签的方块,忽略其他标签的点击位置。
如何获得一个标签来记住我点击的位置?人们说我应该使用 ArrayLists 或 HashCodes 但我不知道如何实现它们。感谢任何可以提供帮助的人。
编辑:顺便说一句,我已经完成了矩形。它仅显示最后输入的标签。这里是一些sn-ps请求的代码!
我如何在 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);
点击时我的 mouseListener:
@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);
悬停时我的 mouseMotionListener:
@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);
如果您希望我添加更多的 sn-ps,请告诉我! :)
【问题讨论】:
+1 用于并列“Apples”和“Cats” 我会说要提高你的接受率,也许会发布一些你的 mousemotionlistener 的代码" it should detect the point, and a rectangle will show up on that area where I clicked."
-- 但是您没有单击矩形,而是单击了一个点。这会是一个以该点为中心的固定大小的特定大小的矩形吗?如果有,尺寸有多大?此外,按钮上的标签区域实际上可以是一个 JList。
哦,是的,关于那个...当我单击图像以确保激活输入窗格的 mouseListener 时,仍然会出现一个矩形。然后对于矩形的代码,我有这个: g2.drawRect(x-50, y-50, 100, 100);
@alicedimarco:请参阅答案中的更新。
【参考方案1】:
你应该创建一个 HashMap,比如:
Map linkSet = new HashMap();
并且每当您单击绘图并创建标签时,使用 put 方法将 JLabel 和图像上的点添加到集合中,其中 JLabel 作为键,Point 作为值。然后在JLabel的MouseMotionListener中,以你的label为key,通过map的get(...)
方法从集合中获取对应的点。
编辑: 根据 alicedimarco 的评论更正。再次感谢!
编辑 2 我想你想再次使用地图。如果你有一个地图,你可以让它从 JLabel 或 JList 的字符串中检索兴趣点,然后将此点传递给正在绘制图像的类,并让它使用该点来绘制一个矩形。例如,您可以为图像绘制类提供一个名为 displayPoint 的 Point 字段和一个名为 setDisplayPoint(Point p) 的方法。可以这么简单:
public void setDisplayPoint(Point p)
this.displayPoint = p;
repaint();
并假设感兴趣的对象以该点为中心,在paintComponent方法中使用displayPoint:
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 来获取用户选择的标记名称,并将生成的 String 添加到 listDataModel 中,以便在 JList 和 stringPointMap 中一起看到它使用从 MouseEvent 获得的 Point,以便您可以将 String 映射到 Point 并能够检索它:
// !! 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);
【讨论】:
这和HashMap一样吗? @alicedimarco:不,这不一样,因为我搞砸了——你是对的,我错了——它应该 成为一个 HashSet。 ...纠正我的答案,谢谢!!! 哦。好的。哈哈。但我也搜索了这个,这也有效!你没有错!不过我还是有问题:(但是谢谢~ @alicedimarco:如果仍有问题,请根据具体情况更新您的问题或开始一个新问题。 @taeyeon:请参阅 edit 3,了解如何在图像保持组件中监听鼠标点击。【参考方案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...
希望对您有所帮助。
【讨论】:
所以你的意思是我不必为标签和坐标创建一个数组? 如果您将标签和坐标合并到同一个对象中(确保覆盖 toString),那么您可以将该对象存储在 JList 中。 我不明白。对不起,我只是一个java初学者:(你的术语对我来说有点难以理解。 初学者没什么错。 ;-) 我添加了一些示例代码。 尝试检查 JList 的 Javadoc 以确定调用什么方法来获取当前选定的项目。以上是关于还记得鼠标点击的地方吗?数组列表?哈希码?的主要内容,如果未能解决你的问题,请参考以下文章