Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

The Shape interface allows you to create shapes using different classes.

In the code below I create shapes using 3 different classes:

GeneralPath barBell = new GeneralPath();
barBell.append(new Ellipse2D.Double(100, 100, 75, 100), true);
barBell.append(new Rectangle2D.Double(150, 125, 175, 50), true);
barBell.append(new Ellipse2D.Double(300, 100, 75, 100), true);
shapePanel.addShape(barBell, Color.RED);

shapePanel.addShape(new Rectangle2D.Double(100, 300, 75, 150), Color.BLUE);

Polygon triangle = new Polygon();
triangle.addPoint(0, 0);
triangle.addPoint(100, 0);
triangle.addPoint(50, 100);
triangle.translate(400, 250);
shapePanel.addShape(triangle, Color.GREEN);

Resulting in a screen image:

enter image description here

Unfortunately the Shape interface does not provide any functionality for transforming the Shape.

For example to move the Shape to a new location I use the following:

if (dragShape instanceof Path2D)
    ((Path2D)dragShape).transform(AffineTransform.getTranslateInstance(deltaX, deltaY));
else if (dragShape instanceof Polygon)
    ((Polygon)dragShape).translate(deltaX, deltaY);
else if (dragShape instanceof RectangularShape)
{
    RectangularShape rs = (RectangularShape)dragShape;
    Rectangle r = rs.getBounds();
    r.x += deltaX;
    r.y += deltaY;
    rs.setFrame( r );
}

I don't like the instanceof logic.

Is there a more generic approach to dragging any Shape around a panel that doesn't use instanceof logic?

Full example:

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
import javax.swing.*;

public class ShapePanel2 extends JPanel
{
    private ArrayList<ColoredShape> coloredShapes = new ArrayList<ColoredShape>();

    public ShapePanel2()
    {
        DragListener dl = new DragListener();
        addMouseListener(dl);
        addMouseMotionListener(dl);
    }

    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        for (ColoredShape cs : coloredShapes)
        {
            g2.setColor( cs.getForeground() );
            g2.fill( cs.getShape() );
        }
    }

    @Override
    public Dimension getPreferredSize()
    {
        return new Dimension(600, 500);
    }

    public void addShape(Shape shape, Color color)
    {
        ColoredShape cs = new ColoredShape(color, shape);
        coloredShapes.add( cs );
        repaint();
    }

    class ColoredShape
    {
        private Color foreground;
        private Shape shape;

        public ColoredShape(Color foreground, Shape shape)
        {
            this.foreground = foreground;
            this.shape = shape;
        }

        public Color getForeground()
        {
            return foreground;
        }

        public void setForeground(Color foreground)
        {
            this.foreground = foreground;
        }

        public Shape getShape()
        {
            return shape;
        }
    }

    class DragListener extends MouseAdapter
    {
        private Shape dragShape;
        private Point pressed;

        @Override
        public void mousePressed(MouseEvent e)
        {
            if (SwingUtilities.isLeftMouseButton(e))
            {
                pressed = e.getPoint();

                for (int i = coloredShapes.size() - 1; i >= 0; i--)
                {
                    ColoredShape cs = coloredShapes.get(i);

                    if (cs.getShape().contains( pressed ))
                    {
                        coloredShapes.remove(i);
                        coloredShapes.add(cs);
                        repaint();
                        dragShape = cs.getShape();
                        break;
                    }
                }
            }
        }

        @Override
        public void mouseDragged(MouseEvent e)
        {
            if (dragShape != null)
            {
                int deltaX = e.getX() - pressed.x;
                int deltaY = e.getY() - pressed.y;

                if (dragShape instanceof Path2D)
                    ((Path2D)dragShape).transform(AffineTransform.getTranslateInstance(deltaX, deltaY));
                else if (dragShape instanceof Polygon)
                    ((Polygon)dragShape).translate(deltaX, deltaY);
                else if (dragShape instanceof RectangularShape)
                {
                    RectangularShape rs = (RectangularShape)dragShape;
                    Rectangle r = rs.getBounds();
                    r.x += deltaX;
                    r.y += deltaY;
                    rs.setFrame( r );
                }

                pressed = e.getPoint();
                repaint();
            }
        }

        @Override
        public void mouseReleased(MouseEvent e)
        {
            dragShape = null;
        }
    }

    private static void createAndShowGUI()
    {
        ShapePanel2 shapePanel = new ShapePanel2();

        GeneralPath barBell = new GeneralPath();
        barBell.append(new Ellipse2D.Double(100, 100, 75, 100), true);
        barBell.append(new Rectangle2D.Double(150, 125, 175, 50), true);
        barBell.append(new Ellipse2D.Double(300, 100, 75, 100), true);
        shapePanel.addShape(barBell, Color.RED);

        shapePanel.addShape(new Rectangle2D.Double(100, 300, 75, 150), Color.BLUE);

        Polygon triangle = new Polygon();
        triangle.addPoint(0, 0);
        triangle.addPoint(100, 0);
        triangle.addPoint(50, 100);
        triangle.translate(400, 250);
        shapePanel.addShape(triangle, Color.GREEN);

        JFrame frame = new JFrame("ShapePanel2");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(shapePanel);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String[] args)
    {
        java.awt.EventQueue.invokeLater( () -> createAndShowGUI() );
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
111 views
Welcome To Ask or Share your Answers For Others

1 Answer

One approach might be to convert each Shape to a GeneralPath as the Shape is added to the panel.

Now the dragging logic only needs to support a single class that implements the Shape interface:

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
import javax.swing.*;

public class ShapePanel extends JPanel
{
    private ArrayList<ColoredShape> coloredShapes = new ArrayList<ColoredShape>();

    public ShapePanel()
    {
        DragListener dl = new DragListener();
        addMouseListener(dl);
        addMouseMotionListener(dl);
    }

    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        for (ColoredShape cs : coloredShapes)
        {
            g2.setColor( cs.getForeground() );
            g2.fill( cs.getShape() );
        }
    }

    @Override
    public Dimension getPreferredSize()
    {
        return new Dimension(600, 500);
    }

    public void addShape(Shape shape, Color color)
    {
        // Convert the Shape to a GeneralPath so the Shape can be translated
        // to a new location when dragged

        ColoredShape cs = new ColoredShape(color, new GeneralPath(shape));
        coloredShapes.add( cs );
        repaint();
    }

    class ColoredShape
    {
        private Color foreground;
        private GeneralPath shape;

        public ColoredShape(Color foreground, GeneralPath shape)
        {
            this.foreground = foreground;
            this.shape = shape;
        }

        public Color getForeground()
        {
            return foreground;
        }

        public void setForeground(Color foreground)
        {
            this.foreground = foreground;
        }

        public GeneralPath getShape()
        {
            return shape;
        }
    }

    class DragListener extends MouseAdapter
    {
        private GeneralPath dragShape;
        private Point pressed;

        @Override
        public void mousePressed(MouseEvent e)
        {
            //  the clicked Shape will be moved to the end of the List
            //  so it is painted on top of all other shapes.

            if (SwingUtilities.isLeftMouseButton(e))
            {
                pressed = e.getPoint();

                for (int i = coloredShapes.size() - 1; i >= 0; i--)
                {
                    ColoredShape cs = coloredShapes.get(i);

                    if (cs.getShape().contains( pressed ))
                    {
                        coloredShapes.remove(i);
                        coloredShapes.add(cs);
                        repaint();
                        dragShape = cs.getShape();
                        break;
                    }
                }
            }
        }

        @Override
        public void mouseDragged(MouseEvent e)
        {
            if (dragShape != null)
            {
                int deltaX = e.getX() - pressed.x;
                int deltaY = e.getY() - pressed.y;

                dragShape.transform(AffineTransform.getTranslateInstance(deltaX, deltaY));

                pressed = e.getPoint();
                repaint();
            }
        }

        @Override
        public void mouseReleased(MouseEvent e)
        {
            dragShape = null;
        }
    }

    private static void createAndShowGUI()
    {
        ShapePanel shapePanel = new ShapePanel();

        GeneralPath barBell = new GeneralPath();
        barBell.append(new Ellipse2D.Double(100, 100, 75, 100), true);
        barBell.append(new Rectangle2D.Double(150, 125, 175, 50), true);
        barBell.append(new Ellipse2D.Double(300, 100, 75, 100), true);
        shapePanel.addShape(barBell, Color.RED);

        shapePanel.addShape(new Rectangle2D.Double(100, 300, 75, 150), Color.BLUE);

        Polygon triangle = new Polygon();
        triangle.addPoint(0, 0);
        triangle.addPoint(100, 0);
        triangle.addPoint(50, 100);
        triangle.translate(400, 250);
        shapePanel.addShape(triangle, Color.GREEN);

        JFrame frame = new JFrame("ShapePanel");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(shapePanel);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String[] args)
    {
        java.awt.EventQueue.invokeLater( () -> createAndShowGUI() );
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share

548k questions

547k answers

4 comments

86.3k users

...