Java Swing實現(xiàn)窗體添加背景圖片的2種方法詳解
本文實例講述了Java Swing實現(xiàn)窗體添加背景圖片的2種方法。分享給大家供大家參考,具體如下:
在美化程序時,常常需要在窗體上添加背景圖片。通過搜索和測試,發(fā)現(xiàn)了2種有效方式。下面分別介紹。
1. 利用JLabel加載圖片
利用JLabel自帶的setIcon(Icon icon)加載icon,并設置JLabel對象的位置和大小使其完全覆蓋窗體。這是一個很取巧的辦法,代碼非常簡單,如下所示。
JLabel lbBg = new JLabel(imageIcon); lbBg.setBounds(0, 0, frameSize.width, frameSize.height); this.getContentPane().add(lbBg);
然而這種方法有幾個要注意的點:
(1)不能使用布局管理器
此時你需要將布局管理器設置為null,然后精確控制所有控件的大小和位置。否則,JLabel無法完整覆蓋窗體。
(2)應當先添加背景JLabel,再添加其它控件。否則其它控件將被JLabel所遮擋(為什么不是后添加的遮擋先添加的?)。
(3)由于控件及窗體的尺寸需要手動控制,因此無法對背景圖片進行縮放。
2. 重載JPanel的paintComponent(Graphics g)方法
通過重載該方法,在JPanel的繪制階段將指定圖片繪制上去即可。由于背景是繪制出來的,因此不會對布局有任何影響。
示例代碼如下:
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, d.width, d.height, this);
MainFrame.instance().repaint();
}
下面是一個完整的demo。
package frame;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class ImageFrame extends JFrame {
class ImagePanel extends JPanel {
Dimension d;
Image image;
public ImagePanel(Dimension d, Image image) {
super();
this.d = d;
this.image = image;
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, d.width, d.height, this);
MainFrame.instance().repaint();
}
}
Dimension frameSize = new Dimension(500, 300);
ImageIcon imageIcon = new ImageIcon(this.getClass().getResource(
"/images/bg.jpg"));
public ImageFrame() {
// 設置窗體屬性
setSize(frameSize);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setIconImage(imageIcon.getImage());
setUndecorated(true);
}
public void addImageByJLable() {
setLayout(null);
// 設置背景
JLabel lbBg = new JLabel(imageIcon);
lbBg.setBounds(0, 0, frameSize.width, frameSize.height);
this.getContentPane().add(lbBg);
addComponents();
setVisible(true);
}
public void addImageByRepaint() {
ImagePanel imagePanel = new ImagePanel(frameSize, imageIcon.getImage());
setContentPane(imagePanel);
addComponents();
setVisible(true);
}
private void addComponents() {
JButton btn1 = new JButton("haha");
btn1.setBounds(10, 20, 60, 30);
this.getContentPane().add(btn1);
JTextField jtf = new JTextField("22222222222");
jtf.setBounds(200, 100, 80, 30);
this.getContentPane().add(jtf);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
ImageFrame imageFrame = new ImageFrame();
// imageFrame.addImageByJLable();
imageFrame.addImageByRepaint();
}
}
運行效果如下:

圖1 使用JLabel加載圖片效果
圖1可見,使用JLabel時,由于未圖片尺寸與窗體尺寸不一致,導致圖片只顯示出一部分;且有一個控件被遮擋了。注意:通過精細設置尺寸和添加控件順序,可以達到較為滿意的效果的。

圖2 使用重繪方式加載圖片
圖2可見,不需要可以設置匹配尺寸和控件的添加順序,即可得到比較滿意的效果。
補充說明:Swing 重繪 repaint,updateUI區(qū)別
repaint
public void repaint()重繪此組件。
如果此組件是輕量組件,則此方法會盡快調用此組件的 paint 方法。否則此方法會盡快調用此組件的 update 方法。
注:有關 AWT 和 Swing 所用繪制機制的更多信息,包括如何編寫最高效的繪制代碼的信息 。
updateUI
public void updateUI()UIManager 發(fā)出的關于 L&F 已經(jīng)更改的通知。用 UIManager 的最新版本替換當前的 UI 對象。覆蓋: 類 JComponent 中的 updateUI另請參見: JComponent.updateUI()
可能大家都試過在swing的事件監(jiān)聽中動態(tài)添加組件,但是JFrame卻不會動態(tài)顯示,只有變大變?。▽嶋H是重畫了)才會顯示。repaint,updateUI可以,用validate發(fā)現(xiàn)也可以。
API中對repaint()方法是這樣描述的,調度完當前所有未完成的事件后重新繪制該組件,所以repaint方法不總是馬上執(zhí)行。
package awtDemo;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
@SuppressWarnings("serial")
public class Ss extends JFrame {
Container con = this.getContentPane();
JButton jb1 = new JButton("jb1");
JButton jb2 = new JButton("jb2");
JLabel jl1 = new JLabel("jl1");
FlowLayout gly = new FlowLayout();
JPanel jp = new JPanel(gly);
public Ss() {
con.add(jp);
jp.add(jb1);
jp.add(jb2);
MyListener ml = new MyListener();
jb1.addMouseListener(ml);
this.setSize(300, 200);
this.setVisible(true);
}
private class MyListener extends MouseAdapter {
@Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
try {
JButton jb3 = new JButton("jb3");
jp.add(jb3);
// jp.updateUI();//可以正常顯示
jp.repaint();//API中對repaint()方法是這樣描述的,調度完當前所有未完成的事件后重新繪制該組件,repaint方法不總是馬上執(zhí)行,所以只有調整大小才可以顯示。
//主要就是下面的invalidate和validate
//當然,用jp來invalidate和validatae也是可以的
// jp.invalidate();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
public static void main(String s[]) {
Ss sss = new Ss();
sss.setVisible(true);
}
}
swing重繪主要有四個關鍵方法:paint(),repaint(),revalidate(),paintImmediately();
而進行繪制時后它會依次調用update(),paint(),paintComponent(),paintBorder(),paintChildren()進行繪制;
那么repaint()方法為什么會延時呢?
調用repaint()會導致一個區(qū)域被增加到重繪列表隊列中,且被預定重繪。產(chǎn)生一個防止到系統(tǒng)事件隊列中的請求,
一旦該請求被處理,內部工具自動毀掉組件的paintImmediately()方法。然后該方法立即執(zhí)行繪制;
也就是說通常情況下repaint()它是不會立即執(zhí)行的,調用它后會有一個等待處理的過程。但repaint比較高效,會推遲實際的繪制并將多余的請求壓縮到單個 paint 調用中。
所以如何解決它的repaint()延時問題呢?
1.讓它立即執(zhí)行:使用paintImmediately()。
2.使用SwingUtilities工具類中的invokeLater(Runnable doRun)方法;把你要在repaint()后執(zhí)行的操作寫在要執(zhí)行的線程中;(它會把這個方法也加入到java內部事件隊列中,它排在repaint()之后,所以一般情況下,它是等repaint()執(zhí)行完之后才會執(zhí)行,雖然這樣達到效果,但并不理想);
更多關于java相關內容感興趣的讀者可查看本站專題:《Java數(shù)據(jù)結構與算法教程》、《Java字符與字符串操作技巧總結》、《Java操作DOM節(jié)點技巧總結》、《Java文件與目錄操作技巧匯總》和《Java緩存操作技巧匯總》
希望本文所述對大家java程序設計有所幫助。
相關文章
SpringBoot項目在IntelliJ IDEA中如何實現(xiàn)熱部署
spring-boot-devtools是一個為開發(fā)者服務的一個模塊,其中最重要的功能就是自動應用代碼更改到最新的App上面去。,這篇文章主要介紹了SpringBoot項目在IntelliJ IDEA中如何實現(xiàn)熱部署,感興趣的小伙伴們可以參考一下2018-07-07
Spring中的@Value和@PropertySource注解詳解
這篇文章主要介紹了Spring中的@Value和@PropertySource注解詳解,@PropertySource:讀取外部配置文件中的key-value保存到運行的環(huán)境變量中,本文提供了部分實現(xiàn)代碼,需要的朋友可以參考下2023-11-11
java file.renameTo返回false的原因及解決方案
這篇文章主要介紹了java file.renameTo返回false的原因及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07
Spring Security將用戶數(shù)據(jù)存儲到數(shù)據(jù)庫的方法
這篇文章主要介紹了Spring Security將用戶數(shù)據(jù)存儲到數(shù)據(jù)庫的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-09-09
關于Shiro過濾器配置方式(ShiroFilterFactoryBean)
這篇文章主要介紹了關于Shiro過濾器配置方式(ShiroFilterFactoryBean),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-12-12

