【问题标题】:putting marks on ImageIcon in JLabel在 JLabel 中的 ImageIcon 上添加标记
【发布时间】:2012-12-26 12:37:56
【问题描述】:

所以我试图找到一种方法来修改 Java 中的图像。换句话说,如果用户单击图像,则会在用户刚刚单击的位置放置一个标记。 我有一个 ImageIcon 放入 JLabel 中。 到目前为止,我采取的方法是使用 JLayeredPanel 将另一个 JPanel 放在 JLabel 之上,然后在这个 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 swing jlabel imageicon jlayeredpane


    【解决方案1】:

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

    我也会考虑使用JXLayer(Java 7 中的又名JLayer)。最好将其描述为组件的玻璃板(在类固醇上)。查看如何装饰组件了解更多详情...

    使用 JLayer 示例更新

    这是一个使用 Java 7 的 JLayer 的示例。 JLayerJXLayer 之间有一些细微的差别,但转换它并不需要太多...

    (对不起,无法抗拒之前的诱惑)

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

    蓝色边框是作为图层一部分的渲染器,它为您提供了可以点击的指南 - 我这样做是为了测试和演示

    【讨论】:

    • 为了更高效,如果不想保留原始图像甚至不关心点列表,您可以使用 theImageIcon.getImage().getGraphics() 然后绘制具有该图形对象的点。通过这样做,您将直接绘制到 ImageIcon 的缓冲区。
    • @nhydock 这是一个公平的观点 - 所有这一切都归结为“OP想要什么”;)
    • @abcXYZ 我还添加了一个JLayer 示例,它可能会更好地满足您的需求
    • MadProgrammer 非常感谢!这绝对对我有很大帮助! @nhydock我试图使用图像图标的图形直接写入原始图像,但它似乎不起作用。所以我在 TestPane ImageIcon icon = new ImageIcon(backgroundd); Graphics origG = new i.getImage().getGraphics(); //... as is origG.setColor(Color.RED); for (Point p : clickPoints) origG.fillOval(p.x - 4, p.y - 4, 8, 8); 的paintComponent() 方法中做这样的事情,它不会在我单击的地方绘制圆圈。我错过了什么?谢谢。
    • @abcXYZ 您需要将点从父上下文转换为本地上下文。您可能需要使用代码示例更新您的问题。
    【解决方案2】:

    您想要使用另一个窗格的方法是正确的。在 Java 中,实际上已经有一个专门为此目的而设计的玻璃窗格。通读本教程http://docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html,它应该可以帮助您理解。

    【讨论】:

    • 哦,我已经读过,但问题是我的图像没有覆盖整个根窗格,所以我显然也不希望玻璃窗格这样做。我只希望用户能够在图片上标记点。你对此有什么建议吗?谢谢
    • 即使玻璃窗格覆盖整个框架,当它们单击时您实际上不必显示任何内容,除非它们在图片范围内。玻璃板的其余部分将是透明的,因此玻璃板是否占据整个框架无关紧要。
    • for example,其中GlassPane返回与RootPane相同的Bound
    • @Jeff todays Java7 实现了JLayer,基于JXLayer(Java6),非常好的API
    • @mKorbel 是的,如果 OP 使用的是 Java 7,那将会很有用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-11
    • 2014-05-09
    • 1970-01-01
    • 2011-01-15
    • 2012-03-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多