Jframe - рисование прямоугольников не работает

У меня есть этот код, который предназначен для рисования прямоугольника поверх предварительно загруженного изображения, но он не работает.

Когда я добавляю класс рисования во фрейм, он перезаписывает изображение, то есть я не вижу предварительно загруженное изображение, но все же позволяет рисовать прямоугольники.

Кроме того, вместо того, чтобы помещать 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 из нарисованного прямоугольника (согласно системе getbounds2d).

если вы удалите frame.add(new paintRectangles());, вы сможете увидеть, как должна выглядеть рамка (но без возможности рисовать прямоугольники)


person Rusty Shackleford    schedule 22.10.2017    source источник
comment
Выскакивает ряд вопросов. Во-первых, вы явно не понимаете, как работает BorderLayout и что он будет делать, если вы попытаетесь добавить два компонента в одну и ту же позицию. Во-вторых, переопределение paint не является рекомендуемым подходом к выполнению пользовательского рисования, вы должны использовать paintComponent и, если у вас нет четкого понимания того, как работает рисование, вызовите super.paintComponent, прежде чем выполнять какое-либо пользовательское рисование. В-третьих, вы, похоже, пытаетесь наложить компонент поверх панели прокрутки, что в текущей конфигурации не позволит панели прокрутки реагировать на события мыши.   -  person MadProgrammer    schedule 23.10.2017
comment
Это также означает, что если содержимое панели прокрутки перемещается, то, что вы нарисовали сверху, не будет прокручиваться вместе с ним.   -  person MadProgrammer    schedule 23.10.2017
comment
Моя общая рекомендация такова: почитайте о менеджерах компоновки, чтобы лучше понять, как они работают. Прочтите, как работает система рисования в Swing, чтобы лучше понять, как вы можете работать с ней для достижения желаемых результатов. Начните с одного компонента, который может рисовать само изображение, а затем к которому вы можете добавить свои собственные требования к рисованию, это значительно уменьшит проблемы, которые у вас есть в настоящее время, и новые проблемы, которые у вас возникнут.   -  person MadProgrammer    schedule 23.10.2017


Ответы (2)


Вы можете добавить paintRectangles (кстати, это должны быть PaintRectangles) в 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));
    }
}

Дополнительные сведения см. в разделе Как использовать многоуровневые панели.

person c0der    schedule 23.10.2017
comment
Извините, c0der, меня не было в стране неделю, поэтому я не смог попробовать это. Это действительно работает, спасибо. Вы правы в своих предыдущих комментариях - я попытался немного опередить свое текущее понимание здесь, пытаясь решить свою проблему, но я нарушаю одно из первых правил, которые я прочитал об обучении коду - лучше понять код чем просто слепое использование кода, который вы не понимаете. Буду изучать предоставленные вами статьи, спасибо - person Rusty Shackleford; 30.10.2017
comment
Я думаю, что у меня есть комментарии о непонимании Jframe, перепутанные с комментариями MadProgrammers. Так что игнорируйте этот бит и спасибо за решение! - person Rusty Shackleford; 30.10.2017

Выскакивает ряд вопросов.

Во-первых, вы явно не понимаете, как работает 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));
    }
}

Недостатком этой проблемы является то, что у вас нет контроля над размещением изображения, а также у вас нет контроля над размером панели наложения, поэтому размер метки может измениться, и вся ваша картина больше не будет соответствовать значку.

Лучшим решением было бы нарисовать изображение на той же панели. Таким образом, вы получаете полный контроль над положением изображения и положением фигур и можете контролировать, как они могут смещаться, если хотите.

person MadProgrammer    schedule 22.10.2017