在JLabel中将标记放在ImageIcon上 [英] putting marks on ImageIcon in JLabel

查看:120
本文介绍了在JLabel中将标记放在ImageIcon上的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我试图找到一种在Java中修改图像的方法。换句话说,如果用户点击图像,则标记将放在用户刚刚点击的位置。
我有一个我放在JLabel中的ImageIcon。
到目前为止,我采用的方法是使用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容器=新的LayeredPane();
container.add(lb,1);
container.add(glass,2);

// ... ...

但这种方式似乎没有工作。我从未看到背景图像(lb中的图像)。
所以我想知道我是否在正确的轨道上?或者是否有更简洁的方法来实现这一目标?

解决方案

使用 JLayeredPane 没有错code>或像这样的玻璃窗格,个人而言,我发现它很麻烦,因为在大型应用程序中,你倾向于将这些层用于任何数量的事情,因此它变得非常复杂非常快。 / p>

我更喜欢把它保留在家庭中,可以这么说......



就个人而言,我会用自定义组件。这将工作流程隔离到一个非常特定的位置,使您可以更轻松地提供您可能喜欢的自定义...



 公共类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框架= 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);
}

});
}

公共类TestPane扩展JPanel {

私有BufferedImage背景;
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);
}
}

}

}

我还考虑在Java 7中使用 JXLayer (AKA JLayer )。这最好描述为组件的玻璃板(类固醇)。查看如何装饰组件以获取更多详细信息...



使用JLayer更新示例



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



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



 公共类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(层);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch(Exception exp){
exp.printStackTrace();
}
}
});
}

公共类MarkLayerUI扩展了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 。创建();
super.paint(g2d,c);
g2d.setColor(Color.BLUE);
g2d.drawRect(0,0,c.getWidth() - 1,c.getHeight() - 1);
列表<点> 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();
}
}
}

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


So I'm trying to find a way to modify an image in Java. In other words, if user clicks on the image, a mark will be put at the point where the user just clicked. I have an ImageIcon which I put in a JLabel. So far, the approach I took was to use JLayeredPanel to put another JPanel on top of the JLabel and draw on this 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);

//...

But this way doesn't seem to work. I never see the background image (the image in lb). So I was wondering if I'm even on the right track at all? Or is there a cleaner way to achieve this?

解决方案

There's nothing wrong with using a JLayeredPane or the glass pane for something like this, personally, I find it troublesome, because in a large application, you tend to want to use these layers for any number of things, so it becomes very complicated very fast.

I prefer to keep it "in the family" so to speak...

Personally, I would use a custom component. This isolates the work flow to a very particular location and makes it easier to provide the customisations that you might like...

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

    }

}

I'd also consider using JXLayer (AKA JLayer in Java 7). This is best described as a glass pane for components (on steroids). Check out How to decorate components for more details...

Updated with JLayer Example

This is an example using Java 7's JLayer. There are some slight differences between JLayer and JXLayer, but it wouldn't take much to convert it...

(Sorry, couldn't resist the temptation of having ago)

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

The blue border is renderer as part of the layer, this gives you a guide as to where you can click - I did this for testing and demonstration purposes

这篇关于在JLabel中将标记放在ImageIcon上的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆