Java 旋转JPanel中绘制的内容,保持质心的位置
我想根据旋转角度并围绕相应面板的质心旋转在paintComponentGraphics g方法中绘制的内容 以下是我最初的想法: 控制面板textfield+按钮,用于设置角度(以度为单位),从0到359。包含一个白色小面板的主面板。当用户单击“设置角度”按钮时,必须更新小白色面板的设置边界并重新绘制。在任何情况下,小白色面板必须以其质心为中心 这是我想要的90度和135度: 这是我的SSCCE,它不工作了。你能告诉我我做错了什么吗Java 旋转JPanel中绘制的内容,保持质心的位置,java,swing,rotation,jpanel,awt,Java,Swing,Rotation,Jpanel,Awt,我想根据旋转角度并围绕相应面板的质心旋转在paintComponentGraphics g方法中绘制的内容 以下是我最初的想法: 控制面板textfield+按钮,用于设置角度(以度为单位),从0到359。包含一个白色小面板的主面板。当用户单击“设置角度”按钮时,必须更新小白色面板的设置边界并重新绘制。在任何情况下,小白色面板必须以其质心为中心 这是我想要的90度和135度: 这是我的SSCCE,它不工作了。你能告诉我我做错了什么吗 import java.awt.BorderLayout; i
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);
}
}
我设法重置了白色小面板的边界,但无法正确旋转文本。很难准确地描述什么不起作用。请执行该代码并自行检查
谢谢。找到了。帮助了我。我更新了paintComponentGraphics 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);
}
}
关键在于执行以下调用:
translate(x, y);
rotate(theta);
translate(-x, -y);
但在我的情况下,我不想翻译回与原文完全相同的数量。我必须使用字符串的维度。为此,我将使用3个连接的仿射变换实例。1将中心移动到原点。2旋转3将中心移动到原始位置。感谢您的评论@AndrewThompson。但是我调用g2.rotateangle、getWidth/2、getHeight/2;,不是已经在做什么了吗@AndrewThompson:或者,此变体将所有内容连接到一个实例中。@AndrewThompson:另请参见@Marcdeverdehan:是否要围绕字符串的中心旋转?