使图像指向 java 中的特定位置

make image point toward specific location in java

在将其标记为重复之前

我在互联网上搜索了很多,并尝试了所有解决方案,但没有人按照我的方式来做。在我的例子中,轮换是一个很好的 class.

我创建了一个 java class 继承了 JLabel class,在我的 class 我有一个箭头 BufferedImage使用 paintComponent(Graphics g) 方法绘制。

我试图让箭头指向一个特定的点(这是我从不同的方法得到的)但是出了点问题,箭头旋转到错误的方向。

我认为: 它计算不正确,因为 imageLocation 是相对于标签的。

这是我的代码:

package pkg1;

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import javax.swing.*;

public final class ImageLabel extends JLabel {

   private float angle = 0.0f; // in radians
   private Point imageLocation = new Point();
   private File imageFile = null;
   private Dimension imageSize = new Dimension(50, 50);
   private BufferedImage bi;

   private BufferedImage resizeImage(BufferedImage originalImage, int img_width, int img_height) {
      int type = originalImage.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : originalImage.getType();
      BufferedImage resizedImage = new BufferedImage(img_width, img_height, type);
      Graphics2D g = resizedImage.createGraphics();
      g.drawImage(originalImage, 0, 0, img_width, img_height, null);
      g.dispose();

      return resizedImage;
   }

   @Override
   public void paintComponent(Graphics g) {
      super.paintComponent(g);
      if (bi == null) {
         return;
      }
      imageLocation = new Point(getWidth() / 2 - bi.getWidth() / 2, getHeight() / 2 - bi.getHeight() / 2);
      Graphics2D g2 = (Graphics2D) g;
      g2.rotate(angle, imageLocation.x + bi.getWidth() / 2, imageLocation.y + bi.getHeight() / 2);
      g2.drawImage(bi, imageLocation.x, imageLocation.y, null);
   }

   public void rotateImage(float angle) { // rotate the image to specific angle
      this.angle = (float) Math.toRadians(angle);
      repaint();
   }

   public void pointImageToPoint(Point target) {
      calculateAngle(target);
      repaint();
   }

   private void calculateAngle(Point target) {
      // calculate the angle from the center of the image
      float deltaY = target.y - (imageLocation.y + bi.getHeight() / 2);
      float deltaX = target.x - (imageLocation.x + bi.getWidth() / 2);
      angle = (float) Math.atan2(deltaY, deltaX);
      if (angle < 0) {
         angle += (Math.PI * 2);
      }
   }
}

好吧,我突然想到两件事...

  1. 如果你从标签上下文之外获取一个Point,你将不得不将该点转换为组件坐标上下文
  2. calculateAngle好像不对

所以从...开始...

private void calculateAngle(Point target) {
  // calculate the angle from the center of the image
  float deltaY = target.y - (imageLocation.y + bi.getHeight() / 2);
  float deltaX = target.x - (imageLocation.x + bi.getWidth() / 2);
  angle = (float) Math.atan2(deltaY, deltaX);
  if (angle < 0) {
     angle += (Math.PI * 2);
  }
}

angle = (float) Math.atan2(deltaY, deltaX); 应该是 angle = (float) Math.atan2(deltaX, deltaY);(交换增量)

您会发现需要将结果调整 180 度才能使图像指向正确的方向

angle = Math.toRadians(Math.toDegrees(angle) + 180.0);

好吧,我是个白痴,但它有效:P

我还会使用 AffineTransform 来平移和旋转图像 - 就个人而言,我发现它更容易处理。

在这个例子中,我作弊了一点。我将 AffineTransform 的平移设置为组件的中心,然后围绕新原点 (0x0) 旋转上下文。然后,我将图像偏移 height/width 的一半进行绘制,从而使其看起来好像图像围绕其中心旋转 - 已经晚了,我累了,它起作用了:P

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private ImageLabel label;

        public TestPane() {
            setLayout(new GridBagLayout());
            label = new ImageLabel();
            add(label);

            addMouseMotionListener(new MouseAdapter() {
                @Override
                public void mouseMoved(MouseEvent e) {
                    label.pointImageToPoint(e.getPoint(), TestPane.this);
                }
            });
        }

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

    }

    public final class ImageLabel extends JLabel {

        private double angle = 0;
        private Point imageLocation = new Point();
        private File imageFile = null;
        private Dimension imageSize = new Dimension(50, 50);
        private BufferedImage bi;

        public ImageLabel() {
            setBorder(new LineBorder(Color.BLUE));
            bi = new BufferedImage(50, 50, BufferedImage.TYPE_INT_ARGB);
            Graphics2D g2d = bi.createGraphics();
            g2d.setColor(Color.RED);
            g2d.drawLine(25, 0, 25, 50);
            g2d.drawLine(25, 0, 0, 12);
            g2d.drawLine(25, 0, 50, 12);
            g2d.dispose();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(bi.getWidth(), bi.getHeight());
        }

        protected Point centerPoint() {
            return new Point(getWidth() / 2, getHeight() / 2);
        }

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (bi == null) {
                return;
            }
            Graphics2D g2d = (Graphics2D) g.create();
            AffineTransform at = g2d.getTransform();
            Point center = centerPoint();
            at.translate(center.x, center.y);
            at.rotate(angle, 0, 0);
            g2d.setTransform(at);
            g2d.drawImage(bi, -bi.getWidth() / 2, -bi.getHeight() / 2, this);
            g2d.dispose();
        }

        public void rotateImage(float angle) { // rotate the image to specific angle
            this.angle = (float) Math.toRadians(angle);
            repaint();
        }

        public void pointImageToPoint(Point target, JComponent fromContext) {
            calculateAngle(target, fromContext);
            repaint();
        }

        private void calculateAngle(Point target, JComponent fromContext) {
            // calculate the angle from the center of the image
            target = SwingUtilities.convertPoint(fromContext, target, this);
            Point center = centerPoint();
            float deltaY = target.y - center.y;
            float deltaX = target.x - center.x;
            angle = (float) -Math.atan2(deltaX, deltaY);
            angle = Math.toRadians(Math.toDegrees(angle) + 180.0);
            repaint();
        }
    }
}

我只想补充一点,为此目的使用 JLabel 有点矫枉过正,一个简单的 JPanelJComponent 可以完成相同的工作并且带来的开销要少得多, 只是说