旋转图像没有明确的背景

时间:2015-04-14 16:09:43

标签: java swing graphics

我已经阅读了很多关于绘制图像的文章,但是当我需要保留背景时,我无法让它们工作。我点击JButton后试图旋转另一张图像上的图像。背景图像在JPanel上生成:

public void paintComponent(Graphics g){

    int index = 0;

    Graphics2D g2 = (Graphics2D) g;

    super.paintComponent(g);    

    try {
        image = ImageIO.read(url1);
        image2 = ImageIO.read(url2);
        image3 = ImageIO.read(url3);
    } catch (IOException e) {
    }


    g.drawImage(image, 0, 0, null);
    g.drawImage(image3, 0, 0, null);

    if(scaleDrawnFlag == 0){

        for(index = 0; index < 60; index ++){
            tx = AffineTransform.getRotateInstance(Math.toRadians(6*index), this.getHeight()/2, this.getWidth()/2);
            op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
            g.drawImage(op.filter(image3, null), 0, 0, null);
        }       

        scaleDrawnFlag = 1;
    }

    g.drawImage(image2, 0, 0, null);

}

这是一个JPanel命名面板,只绘制一次图像以保持刷新性能,仅适用于动画图像。这为转速表绘制了一个刻度,总共60行,其中每一行都是image3的副本

动画图像是通过按下JButton生成的,由以下内容生成:

public void paintComponent(Graphics g){

    super.paintComponent(g);        
    BufferedImage img = new BufferedImage(370, 370, BufferedImage.TRANSLUCENT);
    Graphics2D g2d = img.createGraphics();
    g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f));
    g2d.fillRect(0, 0, img.getWidth(), img.getHeight());
    g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.0f));
    Graphics2D temp = (Graphics2D) g;
    tx = AffineTransform.getRotateInstance(Math.toRadians(degrees), this.getHeight()/2, this.getWidth()/2);
    op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
    temp.drawImage(op.filter(image2, null), 0, 0, null);
    temp.dispose();
}

这是另一个名为overPanel的JPanel,它位于最初的JPanel之上。

但是,当我打电话给方法时:

public void up(){
    degrees ++;
    if(degrees == 360) degrees = 0;
    repaint();
}

public void down(){
    degrees --;
    if(degrees == -360) degrees = 0;
    repaint();
}

在overPanel类中,JPanel完全被清除。动画效果很好,但背景消失了。

我该怎样做才能保留背景?

我还尝试了另一种解决方案,在每次up()和down()调用时再次绘制60行。背景重新绘制,但需要花费太多时间才能完成,因此,旋转转速计指示器的动画会滞后。

2 个答案:

答案 0 :(得分:3)

永远不要丢弃JVM提供给您的Graphics对象。你这样做了:

// temp **is** the same object as g and is the Graphics object given by the JVM
Graphics2D temp = (Graphics2D) g; 
//....
temp.dispose();

并且不应该这样做,因为它完全打破了绘画链。你应该处理你创建的g2d对象。

此外,这也没关系

Graphics2D temp = (Graphics2D) g.create(); // temp **is** a new object
//....
temp.dispose();  // this is OK

其他问题:

  • 我也不会在paintComponent中创建我的BufferedImage,而是将它作为类的一个字段,并将其显示在paintComponent中。
  • 您的热门代码显示忽略的关键异常 - 您不想这样做。
  • 它还显示了在绘画方法中读取图像文件,这会不必要地减慢图形速度。同样,不要这样做,在任何绘画方法之外读取图像,存储结果,并在绘画方法中使用它们。
  • paintComponent方法为protected,而非public。避免不必要地增加其可见性。

在您的最小示例程序中,您的scaleDrawnFlag变量及其关联的if-block似乎搞砸了您。该变量和if块的目的是什么?如果你摆脱变量和if块,你的背景将会持续存在。我自己,我会通过创建一个稳定的背景图像并在每次paintComponent(...)方法中绘制它来做不同的事情。我不会覆盖update(...),因为它是AWT kludge而不是Swing图形。我也试图避免null布局和setBounds(...)像瘟疫一样,因为这导致了非常灵活,严格的GUI,很难调试,维护和增强。例如:

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.*;

@SuppressWarnings("serial")
public class MyMainPanel extends JPanel {
   private MyDrawingPanel myDrawingPanel;

   public MyMainPanel() {
      try {
         myDrawingPanel = new MyDrawingPanel();
      } catch (IOException e) {
         e.printStackTrace();
         System.exit(-1);
      }

      JPanel rightPanel = new JPanel();
      rightPanel.setLayout(new GridLayout(0, 1, 5, 5));
      rightPanel.add(new JButton(new MyUpAction("Up", KeyEvent.VK_U)));
      rightPanel.add(new JButton(new MyDownAction("Down", KeyEvent.VK_D)));

      JPanel rightWrapPanel = new JPanel(new BorderLayout());
      rightWrapPanel.add(rightPanel, BorderLayout.PAGE_START);

      setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
      setLayout(new BorderLayout());
      add(myDrawingPanel, BorderLayout.CENTER);
      add(rightWrapPanel, BorderLayout.LINE_END);
   }

   private class MyUpAction extends AbstractAction {
      public MyUpAction(String name, int mnemonic) {
         super(name);
         putValue(MNEMONIC_KEY, mnemonic);
      }

      @Override
      public void actionPerformed(ActionEvent e) {
         myDrawingPanel.up();
      }
   }

   private class MyDownAction extends AbstractAction {
      public MyDownAction(String name, int mnemonic) {
         super(name);
         putValue(MNEMONIC_KEY, mnemonic);
      }

      @Override
      public void actionPerformed(ActionEvent e) {
         myDrawingPanel.down();
      }
   }

   private static void createAndShowGui() {
      JFrame frame = new JFrame("MyMainPanel");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(new MyMainPanel());
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

@SuppressWarnings("serial")
class MyDrawingPanel extends JPanel {
   private static final String NEEDLE_IMG_PATH = "http://1.bp.blogspot.com/"
         + "-fq-oPGBSLp4/Ttoj7DoAMWI/AAAAAAAABtc/t7gKJlfRQuo/s400/secondHand.png";
   private static final String ORANGE_DISK_IMG_PATH = "http://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/Circle_Fulvous_Solid.svg/200px-Circle_Fulvous_Solid.svg.png";
   private static final String GREEN_LINE_IMG_PATH = "http://www.xtremeskater.com/math/images/circle_radius.png";
   private static final int MAX_DEGREES = 360;

   private int imgWidth = 0;
   private int imgHeight = 0;
   private BufferedImage needleImg = null;
   private BufferedImage orangeDiskImg = null;
   private BufferedImage greenLineImg = null;
   private BufferedImage backgroundImg = null;
   private int degrees; 

   public MyDrawingPanel() throws IOException {
      URL needleUrl = new URL(NEEDLE_IMG_PATH);
      URL orangeDiskUrl = new URL(ORANGE_DISK_IMG_PATH);
      URL greenLineUrl = new URL(GREEN_LINE_IMG_PATH);
      needleImg = ImageIO.read(needleUrl);
      orangeDiskImg = ImageIO.read(orangeDiskUrl);
      greenLineImg = ImageIO.read(greenLineUrl);

      imgWidth = Math.max(orangeDiskImg.getWidth(), 
            greenLineImg.getWidth());
      imgHeight = Math.max(orangeDiskImg.getHeight(),
            greenLineImg.getHeight());
      backgroundImg = new BufferedImage(imgWidth, imgHeight,
            BufferedImage.TYPE_INT_ARGB);
      Graphics2D g2 = backgroundImg.createGraphics();
      drawBackground(g2, imgWidth, imgHeight);
      g2.dispose();
   }

   @Override
   public Dimension getPreferredSize() {
      if (isPreferredSizeSet()) {
         return super.getPreferredSize();
      }
      return new Dimension(imgWidth, imgHeight);
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      if (backgroundImg != null) {
         g.drawImage(backgroundImg, 0, 0, null);
      }
      AffineTransform tx = AffineTransform.getRotateInstance(Math.toRadians(degrees),
            this.getHeight() / 2, this.getWidth() / 2);
      AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
      g.drawImage(op.filter(needleImg, null), 0, 0, null);
   }

   public void up() {
      degrees++;
      degrees %= MAX_DEGREES;
      repaint();
   }

   public void down() {
      degrees--;
      degrees += MAX_DEGREES;
      degrees %= MAX_DEGREES;
      repaint();
   }

   public int getDregrees() {
      return degrees;
   }

   private void drawBackground(Graphics2D g2, int biWidth, int biHeight) {
      int index;
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
      g2.drawImage(orangeDiskImg, 0, 0, null);
      g2.drawImage(greenLineImg, 0, 0, null);
      AffineTransform tx = AffineTransform.getRotateInstance(Math.toRadians(6),
            biWidth / 2, biHeight / 2);
      for (index = 0; index < 60; index++) {
         g2.transform(tx);
         g2.drawImage(greenLineImg, 0, 0, null);
      }
   }
}

答案 1 :(得分:0)

我找到了使背景永久化的方法,首先将其创建为Buffered图像,然后在每个动作上重新绘制该图像,而不重绘所有原始形式或图像旋转。我的意思是,首先,我创建了多次旋转基本图像的背景。这是使用缓冲图像创建的。然后,在paintComponent()方法上,我重绘了缓冲的图像:

public MyPanel(){
    try {
        image = ImageIO.read(url1);
        image2 = ImageIO.read(url2);
        image3 = ImageIO.read(url3);

    } catch (IOException e) {
    }

    img = createImage();
}

private Image createImage(){

    double index = 0;

  BufferedImage bufferedImage = new BufferedImage(370,370,BufferedImage.TYPE_INT_ARGB);

  Graphics g = bufferedImage.getGraphics();

  for(index = 0; index <= scale; index = index + count){

      tx = AffineTransform.getRotateInstance(Math.toRadians(deg2), 185, 185);
      op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
      g.drawImage(op.filter(image3, null), 0, 0, null);
      deg2 = deg2 + (270.0/(scale/count));
      }

      return bufferedImage;
   }

protected void paintComponent(Graphics g){

    super.paintComponent(g);

    g.drawImage(image, 0, 0, null);     //Indicator drawing
    g.drawImage(img, 0, 0, null);       //Scale drawing


    //Indicator rotation

    tx = AffineTransform.getRotateInstance(Math.toRadians(degrees), this.getHeight()/2, this.getWidth()/2);
    op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
    g.drawImage(op.filter(image2, null), 0, 0, null);   
}

这里是基本示例的完整代码:

package rotateOnImage;

import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Image;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JButton;
import javax.swing.AbstractAction;

import java.awt.event.ActionEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;

import javax.swing.Action;

public class MainFrame extends JFrame {

/**
 * 
 */
private static final long serialVersionUID = 1L;
private JPanel contentPane;
private MyPanel panel = new MyPanel();
private final Action upAction = new upAction();
private final Action dnAction = new dnAction();

/**
 * Launch the application.
 */
public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                MainFrame frame = new MainFrame();
                frame.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

/**
 * Create the frame.
 */
public MainFrame() {
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setBounds(100, 100, 345, 227);
    contentPane = new JPanel();
    contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
    setContentPane(contentPane);
    contentPane.setLayout(null);

    JButton btnNewButton = new JButton("UP");
    btnNewButton.setAction(upAction);
    btnNewButton.setBounds(212, 12, 117, 25);
    contentPane.add(btnNewButton);

    JButton button = new JButton("DN");
    button.setAction(dnAction);
    button.setBounds(212, 49, 117, 25);
    contentPane.add(button);

    panel.setBounds(0, 0, 200, 200);

    contentPane.add(panel);
}
private class upAction extends AbstractAction {
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    public upAction() {
        putValue(NAME, "UP");

    }
    public void actionPerformed(ActionEvent e) {

        panel.up();
    }
}
private class dnAction extends AbstractAction {
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    public dnAction() {
        putValue(NAME, "DN");

    }
    public void actionPerformed(ActionEvent e) {

        panel.down();
    }
}
}

class MyPanel extends JPanel{

private static final long serialVersionUID = 1L;
/**
 * 
 */

private int degrees  = 0;
private AffineTransform tx = null;
private AffineTransformOp op = null;

private BufferedImage image1 = null;
private BufferedImage image2 = null;
private BufferedImage image3 = null;

Image img = null;

public static final String IMAGE_PATH1 = "http://1.bp.blogspot.com/"+"-fq-oPGBSLp4/Ttoj7DoAMWI/AAAAAAAABtc/t7gKJlfRQuo/s400/secondHand.png";
public static final String IMAGE_PATH2 = "http://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/Circle_Fulvous_Solid.svg/200px-Circle_Fulvous_Solid.svg.png";
public static final String IMAGE_PATH3 ="http://www.xtremeskater.com/math/images/circle_radius.png";

public MyPanel(){

    try {
        URL url1 = new URL(IMAGE_PATH1);
        URL url2 = new URL(IMAGE_PATH2);            
        URL url3 = new URL(IMAGE_PATH3);
        image1 = ImageIO.read(url1);
        image2 = ImageIO.read(url2);
        image3 = ImageIO.read(url3);
    } catch (IOException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }

    img = createImage();
    }

public void up(){
    degrees ++;
    if(degrees == 360) degrees = 0;
    repaint();
}

public void down(){
    degrees --;
    if(degrees == -360) degrees = 0;
    repaint();
}

public int getDregrees(){
    return degrees;
}

private Image createImage(){

    double index = 0.0;

    BufferedImage bufferedImage = new BufferedImage(200,200,BufferedImage.TYPE_INT_ARGB);

    Graphics g = bufferedImage.getGraphics();

    for(index = 0.0; index <= 36; index ++){

      tx = AffineTransform.getRotateInstance(Math.toRadians(index*10), 100, 100);
      op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
      g.drawImage(op.filter(image3, null), 0, 0, null);
  }

      return bufferedImage;
}

public void update(Graphics g){
    paint(g);
}

protected void paintComponent(Graphics g){


    super.paintComponent(g);    

    g.drawImage(image2, 0, 0, null);        //Dibujado de la manecilla
    g.drawImage(img, 0, 0, null);       //Dibujado de la escala 


    //Rotación de la manecilla

    tx = AffineTransform.getRotateInstance(Math.toRadians(degrees), this.getHeight()/2, this.getWidth()/2);
    op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
    g.drawImage(op.filter(image1, null), 0, 0, null);
}
}