2014-01-25 77 views
4

讓我說我有一個圖像。我把圖像放在一個JPanel中,並在JFrame中添加JPanel。圖像從框架底部移動到框架頂部,同時使用AffineTransform縮小其大小。該變量使用線程更改。通過線程縮放圖像 - JAVA

所以這裏的下面的代碼:

public class SplashScreen extends JFrame{ 
    Image img1; 
    int w=1,h=1; 
    int x=0,y=0; 
    Thread th = new Thread(new Runnable() { 
    @Override 
    public void run() { 
     while(true){ 
      w-=0.05; 
      h-=0.05; 
      y-=2; 
      x+=1; 

      if(y==-100){ 
       new MainMenu_BlueJay().setVisible(true); 
       dispose(); 
      } 

      repaint(); 
      try { 
       Thread.sleep(10); 
      } catch (InterruptedException ex) { 
       Logger.getLogger(SplashScreen.class.getName()).log(Level.SEVERE, null, ex); 
      } 

     } 
    } 
}); 

JPanel p = new JPanel(); 

public SplashScreen(){ 
    setLayout(new BorderLayout()); 

    p.setPreferredSize(new Dimension(900,600)); 
    p.setBackground(Color.black); 
    p.setLayout(new GridLayout()); 

    add(p); 
    setTitle("BlueJay"); 
    setSize(900,600); 

    getContentPane().setBackground(Color.black); 
    setDefaultCloseOperation(EXIT_ON_CLOSE); 
    setLocationRelativeTo(null); 
    setVisible(true); 
    th.start(); 
    requestFocus(); 
    setFocusable(true); 
} 

@Override 
public void paint(Graphics g) { 
    super.paint(g); 
    Graphics2D g2d = (Graphics2D) g; 

    img1 = new ImageIcon("images/Intro/BJ Production 2013.png").getImage(); 
    AffineTransform at = new AffineTransform(); 
    at.scale(w,h); 
    g2d.setTransform(at); 
    g2d.drawImage(img1, x, y, p); 
} 

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

但是我從代碼獲得以上只是黑屏。怎麼了?無論如何,如果我不使用AffineTransform功能(只是從下往上移動),圖像會顯示並移動,但是框架會快速閃爍(閃爍)。

任何想法來解決這個問題,所以我可以移動圖像,同時減小其大小,也解決了閃爍/快速閃爍幀?

+1

首先,你的變量線程訪問應該是volatile的。其次,線程內部的paint調用必須與SwingUtilities.invokeLater() – morpheus05

+0

一起圍繞。那麼如果不使用線程,如何減少變量的值? – noobprogrammer

回答

2

您不應該覆蓋JFrame的paint方法。如果你想畫任何東西,你應該畫一個延伸JPanel的類,在這裏你覆蓋paintComponent方法。

您不應該在繪畫方法中加載圖像。這是非常低效的。您應該只在一次構造函數中加載圖像。

您不應該致電Graphics2D#setTransform()。看一看的JavaDoc在http://docs.oracle.com/javase/7/docs/api/java/awt/Graphics2D.html#setTransform%28java.awt.geom.AffineTransform%29,其中明確規定

警告:此方法應從未用來申請一個新的座標之上將現有變換

你應該想想你wh值。它們應該是大小的的圖像,或者用作比例因子的圖像?將它們設置爲AffineTransform的縮放因子不會產生將圖像縮放到所需大小的效果。目前,它們被聲明爲int的值,所以像w-=0.05這樣的東西無論如何都沒有意義。

您應該清楚如何描述圖像應該執行的動畫。

人可能總結一下:

你不應該寫代碼,並認爲它是「正確的」,只是因爲沒有編譯錯誤;-)

然而,下面的片段可能是第一步朝着自己的目標:

package stackoverflow; 

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Image; 

import javax.swing.ImageIcon; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.SwingUtilities; 

public class SplashScreen extends JFrame 
{ 
    public static void main(String[] args) 
    { 
     SwingUtilities.invokeLater(new Runnable() 
     { 
      @Override 
      public void run() 
      { 
       new SplashScreen(); 
      } 
     }); 
    }  

    private PaintPanel paintPanel; 

    public SplashScreen() 
    { 
     setTitle("BlueJay"); 
     setDefaultCloseOperation(EXIT_ON_CLOSE); 

     getContentPane().setBackground(Color.BLACK); 
     getContentPane().setLayout(new BorderLayout()); 

     paintPanel = new PaintPanel(); 
     getContentPane().add(paintPanel, BorderLayout.CENTER); 

     setSize(900,600); 
     setLocationRelativeTo(null); 
     setFocusable(true); 
     requestFocus(); 
     setVisible(true); 

     startAnimation(); 
    } 

    void startAnimation() 
    { 
     Thread thread = new Thread(new Runnable() 
     { 
      int x = 100; 
      int y = 100; 
      int w = 0; 
      int h = 0; 

      @Override 
      public void run() 
      { 
       try 
       { 
        Thread.sleep(500); 
       } 
       catch (InterruptedException ex) 
       { 
        Thread.currentThread().interrupt(); 
        return; 
       } 

       while (true) 
       { 
        if (y == 200) 
        { 
         // new MainMenu_BlueJay().setVisible(true); 
         dispose(); 
        } 

        x += 2; 
        y += 1; 
        w += 1; 
        h += 1; 
        paintPanel.setImageCoordinates(x, y, w, h); 

        repaint(); 
        try 
        { 
         Thread.sleep(10); 
        } 
        catch (InterruptedException ex) 
        { 
         Thread.currentThread().interrupt(); 
         return; 
        } 

       } 
      } 
     }); 
     thread.start(); 
    } 
} 


class PaintPanel extends JPanel 
{ 
    private final Image image; 
    private int imageX, imageY; 
    private int imageW, imageH; 

    PaintPanel() 
    { 
     image = new ImageIcon("Clipboard02.jpg").getImage(); 
     imageX = 0; 
     imageY = 0; 
     imageW = 0; 
     imageH = 0; 
    } 

    void setImageCoordinates(int imageX, int imageY, int imageW, int imageH) 
    { 
     this.imageX = imageX; 
     this.imageY = imageY; 
     this.imageW = imageW; 
     this.imageH = imageH; 
     repaint(); 
    } 

    @Override 
    protected void paintComponent(Graphics gr) 
    { 
     super.paintComponent(gr); 
     Graphics2D g = (Graphics2D) gr; 

     float scalingX = (float) imageW/image.getWidth(null); 
     float scalingY = (float) imageH/image.getHeight(null); 
     g.scale(scalingX, scalingY); 

     int ix = (int)(imageX/scalingX); 
     int iy = (int)(imageY/scalingY); 
     g.drawImage(image, ix, iy, null); 
    } 
} 
2
  1. 不要在頂層容器烤漆工藝般JFrame。而是使用JPanel並覆蓋其paintComponent方法並呼叫super.paintComponent
  2. 無需調用Thread.sleep()。請使用javax.swing.Timer
  3. 從EDT
  4. 運行程序不paint方法創建一個new ImageIcon。它會在每次調用repaint()時創建新的ImageIcon對象。相反,在構造函數中實例化它。

這裏是代碼的重構。

import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 

public class SplashScreen extends JFrame { 

    Image img1; 
    int w = 900, h = 600; 
    int x = 0, y = 0; 

    public SplashScreen() { 

     setLayout(new BorderLayout()); 

     add(new MyPanel()); 
     setTitle("BlueJay"); 
     setSize(900, 600); 

     getContentPane().setBackground(Color.black); 
     setDefaultCloseOperation(EXIT_ON_CLOSE); 
     setLocationRelativeTo(null); 
     setVisible(true); 

     requestFocus(); 
     setFocusable(true); 

    } 

    private class MyPanel extends JPanel { 

     public MyPanel() { 
      img1 = new ImageIcon(SplashScreen.class.getResource("/resources/stackoverflow5.png")).getImage(); 
      setBackground(Color.black); 
      setLayout(new GridLayout()); 
      Timer timer = new Timer(20, new ActionListener() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        w -= 5; 
        h -= 5; 
        y -= 2; 
        x += 1; 

        if (y == -250) { 
         new MainMenu_BlueJay().setVisible(true); 
         dispose(); 
        } 
        repaint(); 
       } 
      }); 
      timer.start(); 
     } 

     @Override 
     public void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      Graphics2D g2d = (Graphics2D) g; 

      //AffineTransform at = new AffineTransform(); 
      // at.scale(w, h); 
      // g2d.setTransform(at); 
      g2d.drawImage(img1, x, y, w, h, this); 
     } 

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

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

    } 
} 

我不太熟悉Graphics2D,所以我評論了AffirmTransformation的東西,但解決了其他問題。