【问题标题】:Jframe - Drawing Rectangles not workingJframe - 绘制矩形不起作用
【发布时间】:2017-10-22 21:42:01
【问题描述】:

我有这段代码用于在预加载的图像上绘制一个矩形,但它不起作用。

当我将绘图类添加到框架时,它会覆盖图像,这意味着我看不到预加载的图像,但它仍然允许我绘制矩形。

另外,不是将 jframe 放在我的屏幕中间,而是将它放在右上角,我必须最大化它才能看到框架。

代码:

public class defineArea {

public static void main(String[] args) throws IOException {

    displayImage();
}

private static void displayImage() throws IOException {

    BufferedImage image = ImageIO.read(new File("C:\\Users\\Rusty\\Desktop\\temp\\Test_PDF-1.png"));
    ImageIcon icon = new ImageIcon(image);
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JLabel lbl = new JLabel();
    lbl.setIcon(icon);
    JScrollPane jsp = new JScrollPane(lbl);
    frame.add(jsp);
    frame.add(new paintRectangles());
    frame.pack();
    frame.setVisible(true);

}

public static class paintRectangles extends JComponent {
    ArrayList<Shape> shapes = new ArrayList<Shape>();
    Point startDrag, endDrag;

    public paintRectangles() throws IOException {

        this.addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent e) {
                startDrag = new Point(e.getX(), e.getY());
                endDrag = startDrag;
                repaint();
            }

            public void mouseReleased(MouseEvent e) {
                Shape r = makeRectangle(startDrag.x, startDrag.y, e.getX(), e.getY());
                shapes.add(r);
                startDrag = null;
                endDrag = null;
                repaint();
            }
        });

        this.addMouseMotionListener(new MouseMotionAdapter() {
            public void mouseDragged(MouseEvent e) {
                endDrag = new Point(e.getX(), e.getY());
                repaint();
            }
        });
    }

    public void paint(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        Color[] colors = { Color.YELLOW, Color.MAGENTA, Color.CYAN, Color.RED, Color.BLUE, Color.PINK };
        int colorIndex = 0;

        g2.setStroke(new BasicStroke(2));
        g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.50f));

        for (Shape s : shapes) {
            g2.setPaint(Color.BLACK);
            g2.draw(s);
            g2.setPaint(colors[(colorIndex++) % 6]);
            g2.fill(s);
        }

        if (startDrag != null && endDrag != null) {
            g2.setPaint(Color.LIGHT_GRAY);
            Shape r = makeRectangle(startDrag.x, startDrag.y, endDrag.x, endDrag.y);
            g2.draw(r);
            System.out.println(r.getBounds2D());
        }
    }
}

private static Rectangle2D.Float makeRectangle(int x1, int y1, int x2, int y2) {
    return new Rectangle2D.Float(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2));
}

}

有人可以帮忙吗?我基本上是在尝试从绘制的矩形中获取 2d Rectangle 坐标(根据系统 out getbounds2d)。

如果您删除 frame.add(new paintRectangles());,您可以看到框架的外观(但无法绘制矩形)

【问题讨论】:

  • 出现了许多问题。首先,您显然不了解BorderLayout 的工作原理以及如果您尝试将两个组件添加到同一位置会发生什么。其次,覆盖paint 不是执行自定义绘画的推荐方法,您应该使用paintComponent,除非您清楚了解绘画的工作原理,否则在进行任何自定义绘画之前致电super.paintComponent。第三,您似乎试图在滚动窗格顶部覆盖一个组件,在当前配置中,这将阻止滚动窗格对鼠标事件做出反应
  • 这也意味着如果滚动窗格的内容移动,你在顶部绘制的内容将不会随之滚动
  • 我的“一般”建议是 - 阅读布局管理器,更好地了解它们的工作原理。阅读 Swing 中的绘画系统如何工作,更好地了解如何使用它来达到你想要的结果。从一个可以自己绘制图像的组件开始,然后你可以添加你自定义的绘制要求,这将大大减少你当前遇到的问题和你将遇到的新问题

标签: java swing jframe jlayeredpane glasspane


【解决方案1】:

许多问题突然出现。

首先,您显然不了解 BorderLayout 的工作原理以及如果您尝试将两个组件添加到同一位置会发生什么。

其次,不推荐使用覆盖绘画进行自定义绘画,您应该使用paintComponent,除非您清楚了解绘画的工作原理,否则请在进行任何自定义绘画之前致电super.paintComponent

第三,您似乎试图在滚动窗格顶部覆盖一个组件,在当前配置中,这将阻止滚动窗格对鼠标事件做出反应。这也意味着如果滚动窗格的内容移动,您在顶部绘制的内容将不会随之滚动

我的“一般”建议是 - 阅读布局管理器,更好地了解它们的工作原理。阅读如何在 Swing 中工作的绘画系统,更好地了解如何使用它来实现您想要的结果。从可以自己绘制图像的单个组件开始,然后您可以添加自定义绘制要求,这将大大减少您当前遇到的问题以及您将遇到的新问题

先看看:

解决您当前问题的“简单”解决方案是将您的“绘画”面板添加到JLabel。默认情况下,JLabel 没有布局管理器,因此您需要提供一个,例如:

import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                BufferedImage image = ImageIO.read(new File("C:\\Users\\Rusty\\Desktop\\temp\\Test_PDF-1.png"));
                ImageIcon icon = new ImageIcon(image);
                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                JLabel lbl = new JLabel();
                lbl.setIcon(icon);

                lbl.setLayout(new BorderLayout());
                lbl.add(new PaintOverlayPane());

                JScrollPane jsp = new JScrollPane(lbl);
                frame.add(jsp);
                frame.pack();
                frame.setVisible(true);
            }
        });
    }

    public class PaintOverlayPane extends JPanel {

        ArrayList<Shape> shapes = new ArrayList<Shape>();
        Point startDrag, endDrag;

        public PaintOverlayPane() {
            setOpaque(false);
            this.addMouseListener(new MouseAdapter() {
                public void mousePressed(MouseEvent e) {
                    startDrag = new Point(e.getX(), e.getY());
                    endDrag = startDrag;
                    repaint();
                }

                public void mouseReleased(MouseEvent e) {
                    Shape r = makeRectangle(startDrag.x, startDrag.y, e.getX(), e.getY());
                    shapes.add(r);
                    startDrag = null;
                    endDrag = null;
                    repaint();
                }
            });

            this.addMouseMotionListener(new MouseMotionAdapter() {
                public void mouseDragged(MouseEvent e) {
                    endDrag = new Point(e.getX(), e.getY());
                    repaint();
                }
            });
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g); //To change body of generated methods, choose Tools | Templates.
            Graphics2D g2 = (Graphics2D) g;
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            Color[] colors = {Color.YELLOW, Color.MAGENTA, Color.CYAN, Color.RED, Color.BLUE, Color.PINK};
            int colorIndex = 0;

            g2.setStroke(new BasicStroke(2));
            g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.50f));

            for (Shape s : shapes) {
                g2.setPaint(Color.BLACK);
                g2.draw(s);
                g2.setPaint(colors[(colorIndex++) % 6]);
                g2.fill(s);
            }

            if (startDrag != null && endDrag != null) {
                g2.setPaint(Color.LIGHT_GRAY);
                Shape r = makeRectangle(startDrag.x, startDrag.y, endDrag.x, endDrag.y);
                g2.draw(r);
                System.out.println(r.getBounds2D());
            }
        }
    }

    private static Rectangle2D.Float makeRectangle(int x1, int y1, int x2, int y2) {
        return new Rectangle2D.Float(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2));
    }
}

这个问题的缺点是您无法控制图像的位置,也无法控制覆盖面板的大小,因此标签的大小可能会发生变化,并且您的所有绘画将不再匹配图标。

更好的解决方案是在同一个面板中绘制图像。通过这种方式,您可以完全控制图像的位置和形状的位置,并且可以根据需要控制它们如何偏移

【讨论】:

    【解决方案2】:

    您可以将paintRectangles(应该是PaintRectangles btw)添加到JLayeredPane
    该解决方案并不理想,但它正在发挥作用。
    如果没有别的,值得试驾一下来了解这个选项:

    public class DefineArea {
    
        public static void main(String[] args) throws IOException {
    
            displayImage();
        }
        private static void displayImage() throws IOException {
    
            //  URL url = new URL("http://www.digitalphotoartistry.com/rose1.jpg");
            //    BufferedImage image = ImageIO.read(url);
            //    ImageIcon icon= new ImageIcon(image);
    
            URL url = DefineArea.class.getResource("image.jpg");
            BufferedImage image = ImageIO.read(url);
            ImageIcon icon = new ImageIcon(image);
    
            JFrame frame = new JFrame();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            JLabel lbl = new JLabel();
            lbl.setIcon(icon);
    
            JScrollPane jsp = new JScrollPane(lbl);
            frame.add(jsp);
    
            //add glass pane to layered pane
            JComponent glass = new paintRectangles();
            JLayeredPane lp = frame.getLayeredPane();
            int w = icon.getIconWidth(); int h = icon.getIconHeight();
            // Size is needed here, as there is no layout in lp
            //to make it useful you need to dynamically adjust glass size
            glass.setSize(w,h);
            lp.add(glass);
    
            frame.pack();
            frame.setVisible(true);
        }
    
        public static class paintRectangles extends JComponent {
            ArrayList<Shape> shapes = new ArrayList<>();
            Point startDrag, endDrag;
    
            public paintRectangles() throws IOException {
    
                addMouseListener(new MouseAdapter() {
                    @Override
                    public void mousePressed(MouseEvent e) {
                        System.out.println("mousePressed");
                        startDrag = new Point(e.getX(), e.getY());
                        endDrag = startDrag;
                        repaint();
                    }
    
                    @Override
                    public void mouseReleased(MouseEvent e) {
                        Shape r = makeRectangle(startDrag.x, startDrag.y, e.getX(), e.getY());
                        shapes.add(r);
                        startDrag = null;
                        endDrag = null;
                        repaint();
                    }
                });
    
                addMouseMotionListener(new MouseMotionAdapter() {
                    @Override
                    public void mouseDragged(MouseEvent e) {
                        endDrag = new Point(e.getX(), e.getY());
                        repaint();
                    }
                });
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                Graphics2D g2 = (Graphics2D) g;
                g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                Color[] colors = { Color.YELLOW, Color.MAGENTA, Color.CYAN, Color.RED, Color.BLUE, Color.PINK };
                int colorIndex = 0;
    
                g2.setStroke(new BasicStroke(2));
                g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.50f));
    
                for (Shape s : shapes) {
                    g2.setPaint(Color.BLACK);
                    g2.draw(s);
                    g2.setPaint(colors[(colorIndex++) % 6]);
                    g2.fill(s);
                }
    
                if ((startDrag != null) && (endDrag != null)) {
                    g2.setPaint(Color.LIGHT_GRAY);
                    Shape r = makeRectangle(startDrag.x, startDrag.y, endDrag.x, endDrag.y);
                    g2.draw(r);
                    System.out.println(r.getBounds2D());
                }
            }
        }
    
        private static Rectangle2D.Float makeRectangle(int x1, int y1, int x2, int y2) {
            return new Rectangle2D.Float(Math.min(x1, x2), Math.min(y1, y2),
                                                Math.abs(x1 - x2), Math.abs(y1 - y2));
        }
    }
    

    欲了解更多信息,请参阅How to Use Layered Panes

    【讨论】:

    • 对不起,我已经出国一周了,所以无法尝试。这确实有效,谢谢。您在早期的 cmets 中是对的-我试图在此处跳出我目前的理解以尝试解决我的问题,但我违反了我阅读的有关学习代码的第一条规则之一-而不是理解代码而不是盲目地使用你不理解的代码。我会研究自己提供的文章,谢谢
    • 我想我已经把关于不理解 Jframe 的 cmets 与 MadProgrammers cmets 混为一谈 - 所以忽略这一点并感谢您的解决方案!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-19
    • 1970-01-01
    相关资源
    最近更新 更多