旋转JPanel中绘制的内容,保留质心的位置

时间:2014-10-13 12:50:21

标签: java swing rotation jpanel awt

我想根据旋转角度和相应面板的质心周围旋转paintComponent(Graphics g)方法中绘制的内容。

这是我最初的想法:

Initial state

用于设置角度的控制面板(文本字段+按钮)(以度为单位,从0到359)。主面板包含一个小白板。当用户点击“设置角度”按钮时,必须更新小白色面板(setBounds()repaint())。无论如何,小白板必须以其质心为中心。

这就是我想要的90度和135度:

90 degrees state

135 degrees state

这是我的SSCCE(不起作用)。你能告诉我我做错了吗?

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class RotatingPaint {
    private static double angle = 0;
    private static JFrame frame = new JFrame();
    private static JTextField angleField = new JTextField("0", 6);
    private static JButton angleButton = new JButton("Set angle");
    private static JPanel controlPanel = new JPanel();
    private static JPanel mainPanel  = new JPanel();
    private static JPanel littleWhitePanel  = new JPanel() {
        @Override
        protected void paintComponent(Graphics g)
        {
            super.paintComponent(g);
            Graphics2D g2 = (Graphics2D) g;
            Color oldColor = g2.getColor();
            g2.setColor(Color.RED);
            g2.rotate(angle, getWidth() / 2, getHeight() / 2);
            g2.drawString("Hello World", 2, 12);
            // Revert the transformation matrix back to its initial state
            g2.rotate(-angle, -getWidth() / 2, -getHeight() / 2);
            g2.setColor(oldColor);
        }
    };


    public RotatingPaint() {

        // Inits control panel
        angleButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e){
                angle = Math.toRadians(Integer.parseInt(angleField.getText()));
                Rectangle oldBounds = littleWhitePanel.getBounds();
                Rectangle newBounds = getBoundsOfRotatedRectangle(oldBounds);
                littleWhitePanel.setBounds(newBounds);
                mainPanel.repaint();
            }
        });
        controlPanel.add(angleField);
        controlPanel.add(angleButton);

        // Inits main panel
        mainPanel.setPreferredSize(new Dimension(400, 300));
        mainPanel.setLayout(null);
        littleWhitePanel.setBounds(160, 100, 80, 20);
        littleWhitePanel.setBackground(Color.WHITE);
        mainPanel.add(littleWhitePanel);

        // Inits frame
        frame.setLayout(new BorderLayout());
        frame.add(controlPanel, BorderLayout.NORTH);
        frame.add(mainPanel, BorderLayout.CENTER);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        RotatingPaint app = new RotatingPaint();
    }

    /**
     * Applies the rotate transformation to a Point.
     * @param point the point to be rotated
     */
    private void rotatePoint(Point point) {
        Point centroid = new Point((int) littleWhitePanel.getBounds().getCenterX(), (int) littleWhitePanel.getBounds().getCenterY());
        int x = (int) Math.rint(centroid.x
                + (point.x - centroid.x) * Math.cos(angle)
                - (point.y - centroid.y) * Math.sin(angle));
        int y = (int) Math.rint(centroid.y
                + (point.x - centroid.x) * Math.sin(angle)
                + (point.y - centroid.y) * Math.cos(angle));
        point.x = x;
        point.y = y;
    }

    /**
     * @param rectangle the rectangle to be rotated
     * @return the bounding rectangle of the rotated rectangle
     */
    private Rectangle getBoundsOfRotatedRectangle(Rectangle rectangle) {

        // Getting each corner
        List<Point> corners = new ArrayList<Point>();
        Point topLeftCorner = rectangle.getLocation();
        corners.add(topLeftCorner);
        Point topRightCorner = new Point(topLeftCorner);
        topRightCorner.x += rectangle.width;
        corners.add(topRightCorner);
        Point bottomLeftCorner = new Point(topLeftCorner);
        bottomLeftCorner.y += rectangle.height;
        corners.add(bottomLeftCorner);
        Point bottomRightCorner = new Point(bottomLeftCorner);
        bottomRightCorner.x += rectangle.width;
        corners.add(bottomRightCorner);

        // Transforming each corner
        for (Point corner : corners) {
            rotatePoint(corner);
        }

        // Getting the min/max x and the min/max y
        int minX = corners.get(0).x;
        int minY = corners.get(0).y;
        int maxX = corners.get(0).x;
        int maxY = corners.get(0).y;
        for (int i = 1; i < corners.size(); i++) {
            minX = Math.min(minX, corners.get(i).x);
            minY = Math.min(minY, corners.get(i).y);
            maxX = Math.max(maxX, corners.get(i).x);
            maxY = Math.max(maxY, corners.get(i).y);
        }

        return new Rectangle(minX, minY, maxX - minX, maxY - minY);
    }
}

我设法重置小白色面板的边界,但我无法正确旋转文本。很难描述什么不能正常工作。请执行该代码并自行检查。

谢谢。

1 个答案:

答案 0 :(得分:0)

实测值。 This example帮助了我。我更新了paintComponent(Graphics gr)方法,如下所示:

    @Override
    public void paintComponent(Graphics gr) {
        super.paintComponent(gr);
        Graphics2D g2 = (Graphics2D) gr;
        if (angle != 0) {
            // Moving to centroid
            g2.translate(getWidth()/2, getHeight()/2);
            g2.rotate(angle);
            // Moving back but using the string's dimensions
            // instead of the bounds (which have been changed)
            g2.translate(-stringWidth/2, -stringHeight/2);
        }
        g2.drawString("Hello World", 2, 12);
        if (angle != 0) {
            // Revert the transformation matrix back to its initial state
            g2.translate(stringWidth/2, stringHeight/2);
            g2.rotate(-angle);
            g2.translate(-getWidth()/2, -getHeight()/2);
        }
    }

关键是Graphics2D#rotate()执行以下调用:

translate(x, y);
rotate(theta);
translate(-x, -y);

但在我的情况下,我不想翻译与原始翻译完全相同的金额。我不得不使用字符串的尺寸。