[Java] JFrame JPanel 設背景圖片

在 JFrame 和 JPanel 中雖然有背景的設定 .setBackground() 但參數只能是顏色 Color.COLORNAME 或 new Color(r,g,b)。如果背景要放圖片,可能會想到這樣:

import java.awt.Dimension;

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

public class JFrameBackgroundDemo extends JFrame{

  JFrameBackgroundDemo(){
    JPanel myPanel = new JPanel();
            // 用 Dimension 和 JFrame 的 .pack() 可保證大小正確
    myPanel.setPreferredSize(new Dimension(800,600));
    JLabel bgLabel = new JLabel();
    bgLabel.setIcon(new ImageIcon("img/background.png"));
    bgLabel.setLocation(0, 0);
    bgLabel.setVisible(true);

    myPanel.add(bgLabel);

    this.add(myPanel);
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setVisible(true);
    this.pack();
  }
}

背景圖片路徑是 img/ 下的 background.png。想法是用一個 JLabel 使用該圖片然後定位在 (0, 0) 但這不是好辦法,因為他會推開其他 JComponent 而且當其他有動作時會被 JLabel 蓋住(我對 javax 的上下層邏輯實在無法理解),所以改用別的辦法,參考自 StackOverflow : Simplest way to set image as JPanel background,重寫了 JPanel 中的 paintComponent() 方法:

import java.awt.Dimension;

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

public class JFrameBackgroundDemo extends JFrame{

  JFrameBackgroundDemo(){
    JPanel myPanel = new JPanel() {
      @Override          // 重寫 paintComponent() 方法
      public void paintComponent(Graphics g) {
        super.paintComponent(g);

        g.drawImage(new ImageIcon("img/background.png").getImage(), 0, 0, null);
      }                  // 此處的background.png 是 800*600 大小的圖片,定位在 (0,0)
    };
    myPanel.setPreferredSize(new Dimension(800,600));

    this.add(myPanel);
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setVisible(true);
    this.pack();
  }
}

在實現 JPanel 時重寫 paintComponent() 利用 .drawImage 功能來畫背景,這樣的做法不會干擾其他 JComponent 物件。

另外加入 Timer 和實作 ActionListener 可做出背景圖片的移動:


import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

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

public class MovingBackgroundDemo extends JFrame implements ActionListener{

  int bgPositionX = 0;
  Timer bgTimer;

  MovingBackgroundDemo(){
    bgTimer = new Timer(30, this);    // 計時器30毫秒動一次
    bgTimer.start();

    JPanel myPanel = new JPanel() {
      @Override
      public void paintComponent(Graphics g) {
        super.paintComponent(g);

        g.drawImage(new ImageIcon("img/background_double.png").getImage(), bgPositionX, 0, null);
      }                // background_double.png 是兩倍寬度的背景,定位由 bgPositionX 決定
    };

    myPanel.setPreferredSize(new Dimension(800,600));

    this.add(myPanel);
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setVisible(true);
    this.pack();
  }

  @Override
  public void actionPerformed(ActionEvent e) {
    bgPositionX -= 2;              // 每30毫秒讓背景圖片向左移動2px
    if(bgPositionX < -800) {       // 當左移到極限時重置
      bgPositionX = 0;
    }
    repaint();
  }
}

留言