Aligning Shape's Center to JPanel's Center

2019-07-17 15:54发布

问题:

I have been trying to align my java2d shape's center to the JPanel's center with no success. I was able to do it for an image and many 2D shapes like parallelogram using getBounds method but not for rhombus though all of them follow the same pattern. Drastically, when I prepared an SSCCE out of the actual project I could align none of them correctly. I've written a drawShape method for drawing shapes on center. I didn't understand where I'm going wrong. This is SSCCE:

            import java.awt.*;
            import java.awt.geom.*;
            import java.util.*;
            import javax.swing.*;
            public class TestPanel extends JPanel{
                    Point a,b,c,d;
                    Shape trapezium,parallelogram;
                    Random random=new Random();
                    public TestPanel(){
                        a=new Point();
                        b=new Point();
                        c=new Point();
                        d=new Point();
                        rhombusFactory(a,b,c,d);
                        trapezium=getQuadrilateral(a,b,c,d);


                    }
                    private void rhombusFactory(Point a,Point b,Point c,Point d)
                    {       int width=random.nextInt(200-100)+100;
                            int height=random.nextInt(150-50)+50;
                            a.x=0;
                            a.y=0;
                            b.x=a.x+width/2;
                            b.y=a.y+height/2;
                            c.x=a.x+width;
                            c.y=a.y;
                            d.x=a.x+width/2;
                            d.y=a.y-height/2;
                    }
                    private void parallelogramFactory(Point a,Point b,Point c,Point d){
                        int l1=random.nextInt(200-100)+100;
                        int l2=random.nextInt(150-70)+70;
                        int offset=(random.nextInt(2)==0?-1:1)*(random.nextInt(50-20)+20);
                        a.x=0;
                        a.y=0;
                        b.x=a.x+l1;
                        b.y=a.y;
                        d.x=a.x+offset;
                        d.y=a.y+l2;
                        c.x=d.x+l1;
                        c.y=d.y;
                }
                     private Shape getQuadrilateral(Point a,Point b,Point c,Point d){
                         GeneralPath gp=new GeneralPath();
                         gp.moveTo(a.x,a.y);
                         gp.lineTo(b.x,b.y);
                         gp.lineTo(c.x,c.y);
                         gp.lineTo(d.x,d.y);
                         gp.closePath();
                         return gp;
                    }
                    private void drawShape(Graphics2D g,Shape shape){
                        AffineTransform oldt=g.getTransform();
                        Rectangle2D bounds=shape.getBounds2D();
                        double height=bounds.getHeight();
                        double width=bounds.getWidth();
                        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
                        g.setStroke(new BasicStroke(2.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
                        g.translate(this.getWidth()/2,this.getHeight()/2);
                        g.translate(-width/2,-height/2);
                        g.draw(shape.getBounds2D());
                        g.draw(shape);
                        g.setTransform(oldt);
                }
                    public void paintComponent(Graphics g2){
                            super.paintComponent(g2);
                            Graphics2D g=(Graphics2D)g2;
                            drawShape(g,trapezium);
                            //drawShape(g,parallelogram);
                    }
                    public static void main(String args[]){
                            JFrame jf=new JFrame();
                            TestPanel tp=new TestPanel();
                            jf.setLayout(new BorderLayout());
                            jf.add(tp,BorderLayout.CENTER);
                            jf.setSize(500,500);
                            jf.setVisible(true);
                    }
             }

Any help would be appreciated EDIT: I just removed the confusing lines out of the code...

回答1:

You need to account for the bounded x/y location of the Shape:

Rectangle bounds=shape.getBounds(); // changed this
...
//g.translate(this.getWidth()/2,this.getHeight()/2);
//g.translate(-width/2,-height/2);
g.translate((this.getWidth() - width) / 2,(this.getHeight() - height) / 2);
g.translate(-bounds.x, -bounds.y); // added this


回答2:

Your translate is wrong. You should first translate the origin of you drawing space to the center of the panel and then translate the center of your drawing to the origin. You did the latter right, but the first wrong.

Change

g.translate(this.getWidth(),this.getHeight());
g.translate(-width/2,-height/2);

to

g.translate(this.getWidth()/2,this.getHeight()/2);
g.translate(-width/2,-height/2);

Or just

g.translate((this.getWidth() - width) / 2,(this.getHeight() - height) / 2);


回答3:

EDIT:
In method rhombusFactory(), change that:

a.y=0;

to this:

a.y=height/2;

Short expanation:
In your drawShape() method, you place the graphics context's origin where you assume that the upper left corner of the shape's bounds would be (Point: [(getWidth-width)/2, (getHeight()-height)/2]). In your rhombusFactory() method, you set point a at (0, 0), which consequently shifts your shape's upper left corner at (0,-height/2), effectively causing it's not being vertically centered.