Java 在JLabel中的ImageIcon上做标记
所以我试图找到一种用Java修改图像的方法。换句话说,如果用户单击图像,将在用户刚刚单击的位置放置一个标记。 我有一个图像图标,我把它放在一个JLabel中。 到目前为止,我采用的方法是使用JLayeredPanel在JLabel上放置另一个JPanel,并在此JPanel上绘制:Java 在JLabel中的ImageIcon上做标记,java,swing,jlabel,imageicon,jlayeredpane,Java,Swing,Jlabel,Imageicon,Jlayeredpane,所以我试图找到一种用Java修改图像的方法。换句话说,如果用户单击图像,将在用户刚刚单击的位置放置一个标记。 我有一个图像图标,我把它放在一个JLabel中。 到目前为止,我采用的方法是使用JLayeredPanel在JLabel上放置另一个JPanel,并在此JPanel上绘制: //... ImageIcon icon = new ImageIcon("foo.jpg"); JLabel lb = new JLabel(icon); JPanel glass = new JPanel();
//...
ImageIcon icon = new ImageIcon("foo.jpg");
JLabel lb = new JLabel(icon);
JPanel glass = new JPanel();
lb.setBounds(0, 0, 100, 100);
glass.setBounds(0, 0, 100, 100);
glass.setOpaque(false);
LayeredPane container = new LayeredPane();
container.add(lb, 1);
container.add(glass, 2);
//...
但这种方式似乎不起作用。我从未看到背景图像(以磅为单位的图像)。
所以我想知道我是否在正确的轨道上?或者有没有更干净的方法来实现这一点?您想使用另一个窗格的想法是正确的。在Java中,实际上已经有一个专门为此目的而设计的玻璃窗格。通读本教程,它会帮助您理解。使用
JLayeredPane
或玻璃窗格进行类似操作没有什么错,我个人觉得这很麻烦,因为在大型应用程序中,您往往希望将这些层用于任意数量的对象,因此它会变得非常复杂
可以说,我宁愿把它留在“家里”
就个人而言,我会使用自定义组件。这将工作流程隔离到一个非常特殊的位置,并使您更容易提供您可能喜欢的定制
public class MarkImage {
public static void main(String[] args) {
new MarkImage();
}
public MarkImage() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage background;
private List<Point> clickPoints;
public TestPane() {
clickPoints = new ArrayList<>(25);
try {
background = ImageIO.read(getClass().getResource("/Miho_Small.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
clickPoints.add(e.getPoint());
repaint();
}
});
}
@Override
public Dimension getPreferredSize() {
return background == null ? super.getPreferredSize() : new Dimension(background.getWidth(), background.getHeight());
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (background != null) {
int x = (getWidth() - background.getWidth()) / 2;
int y = (getHeight() - background.getHeight()) / 2;
g.drawImage(background, x, y, this);
}
g.setColor(Color.RED);
for (Point p : clickPoints) {
g.fillOval(p.x - 4, p.y - 4, 8, 8);
}
}
}
}
蓝色边框是渲染器作为层的一部分,这为您提供了单击位置的指南-我这样做是为了测试和演示目的哦,我已经读过了,但问题是我的图像没有覆盖整个根窗格,所以我显然也不希望玻璃窗格覆盖整个根窗格。我只希望用户能够在图片上标记点。你对此有什么建议吗?如果玻璃窗格覆盖了整个框架,则当它们单击时实际上不必显示任何内容,除非它们在图片边界内。玻璃窗格的其余部分将是透明的,因此玻璃窗格是否占据整个框架并不重要。右侧,其中
GlassPane
返回与RootPane
@Jeff todaysJava7
基于JXLayer(Java6)
实现的JLayer
相同的绑定,非常好API@mKorbel是的,如果OP使用的是Java 7,这将非常有用。为了更高效,如果不希望保留原始图像或甚至不关心点列表,可以使用theImageIcon.getImage().getGraphics()然后使用该图形对象绘制点。通过这样做,您将直接绘制到ImageIcon的缓冲区。@nhydock这是一个公平的点-所有这些都归结为“OP想要什么”;)@abcXYZ我还添加了一个JLayer
示例,它可能会更好地满足您的需求程序员非常感谢!这确实帮了我很大的忙@nhydock我试图使用图像图标的图形直接写入原始图像,但似乎不起作用。所以我在TestPane的paintComponent()方法中做了类似的事情ImageIcon icon=newimageicon(backgroundd)代码>Graphics origG=new i.getImage().getGraphics()代码>/。。。原样
origG.setColor(Color.RED)代码>用于(点p:clickPoints)或填充椭圆(p.x-4,p.y-4,8,8)代码>它不会在我单击的地方绘制圆。我错过什么了吗?谢谢。@abcXYZ您需要将点从父上下文转换为本地上下文。您可能需要使用代码示例更新您的问题。
public class MarkLayer {
public static void main(String[] args) {
new MarkLayer();
}
public MarkLayer() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
try {
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
JLabel label = new JLabel(new ImageIcon(ImageIO.read(getClass().getResource("/Miho_Small.png"))));
LayerUI<JLabel> layerUI = new MarkLayerUI();
JLayer<JLabel> layer = new JLayer<>(label, layerUI);
frame.add(layer);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (Exception exp) {
exp.printStackTrace();
}
}
});
}
public class MarkLayerUI extends LayerUI<JLabel> {
private Map<JLayer, List<Point>> mapPoints;
public MarkLayerUI() {
mapPoints = new WeakHashMap<>(25);
}
@Override
public void installUI(JComponent c) {
System.out.println("install");
super.installUI(c);
JLayer layer = (JLayer) c;
layer.setLayerEventMask(AWTEvent.MOUSE_EVENT_MASK);
}
@Override
public void uninstallUI(JComponent c) {
super.uninstallUI(c);
mapPoints.remove((JLayer) c);
}
@Override
protected void processMouseEvent(MouseEvent e, JLayer<? extends JLabel> l) {
if (e.getID() == MouseEvent.MOUSE_CLICKED) {
List<Point> points = mapPoints.get(l);
if (points == null) {
points = new ArrayList<>(25);
mapPoints.put(l, points);
}
Point p = e.getPoint();
p = SwingUtilities.convertPoint(e.getComponent(), p, l);
points.add(p);
l.repaint();
}
}
@Override
public void paint(Graphics g, JComponent c) {
Graphics2D g2d = (Graphics2D) g.create();
super.paint(g2d, c);
g2d.setColor(Color.BLUE);
g2d.drawRect(0, 0, c.getWidth() - 1, c.getHeight() - 1);
List<Point> points = mapPoints.get((JLayer) c);
if (points != null && points.size() > 0) {
g2d.setColor(Color.RED);
for (Point p : points) {
g2d.fillOval(p.x - 4, p.y - 4, 8, 8);
}
}
g2d.dispose();
}
}
}