Java Swing實(shí)現(xiàn)窗體添加背景圖片的2種方法詳解
本文實(shí)例講述了Java Swing實(shí)現(xiàn)窗體添加背景圖片的2種方法。分享給大家供大家參考,具體如下:
在美化程序時(shí),常常需要在窗體上添加背景圖片。通過搜索和測(cè)試,發(fā)現(xiàn)了2種有效方式。下面分別介紹。
1. 利用JLabel加載圖片
利用JLabel自帶的setIcon(Icon icon)加載icon,并設(shè)置JLabel對(duì)象的位置和大小使其完全覆蓋窗體。這是一個(gè)很取巧的辦法,代碼非常簡(jiǎn)單,如下所示。
JLabel lbBg = new JLabel(imageIcon); lbBg.setBounds(0, 0, frameSize.width, frameSize.height); this.getContentPane().add(lbBg);
然而這種方法有幾個(gè)要注意的點(diǎn):
(1)不能使用布局管理器
此時(shí)你需要將布局管理器設(shè)置為null,然后精確控制所有控件的大小和位置。否則,JLabel無法完整覆蓋窗體。
(2)應(yīng)當(dāng)先添加背景JLabel,再添加其它控件。否則其它控件將被JLabel所遮擋(為什么不是后添加的遮擋先添加的?)。
(3)由于控件及窗體的尺寸需要手動(dòng)控制,因此無法對(duì)背景圖片進(jìn)行縮放。
2. 重載JPanel的paintComponent(Graphics g)方法
通過重載該方法,在JPanel的繪制階段將指定圖片繪制上去即可。由于背景是繪制出來的,因此不會(huì)對(duì)布局有任何影響。
示例代碼如下:
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, d.width, d.height, this);
MainFrame.instance().repaint();
}
下面是一個(gè)完整的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() {
// 設(shè)置窗體屬性
setSize(frameSize);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setIconImage(imageIcon.getImage());
setUndecorated(true);
}
public void addImageByJLable() {
setLayout(null);
// 設(shè)置背景
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();
}
}
運(yùn)行效果如下:

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

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

