Java Swing實現窗體添加背景圖片的2種方法詳解
本文實例講述了Java Swing實現窗體添加背景圖片的2種方法。分享給大家供大家參考,具體如下:
在美化程序時,常常需要在窗體上添加背景圖片。通過搜索和測試,發(fā)現了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 已經更改的通知。用 UIManager 的最新版本替換當前的 UI 對象。覆蓋: 類 JComponent 中的 updateUI另請參見: JComponent.updateUI()
可能大家都試過在swing的事件監(jiān)聽中動態(tài)添加組件,但是JFrame卻不會動態(tài)顯示,只有變大變小(實際是重畫了)才會顯示。repaint,updateUI可以,用validate發(fā)現也可以。
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ū)域被增加到重繪列表隊列中,且被預定重繪。產生一個防止到系統(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數據結構與算法教程》、《Java字符與字符串操作技巧總結》、《Java操作DOM節(jié)點技巧總結》、《Java文件與目錄操作技巧匯總》和《Java緩存操作技巧匯總》
希望本文所述對大家java程序設計有所幫助。
相關文章
SpringBoot項目在IntelliJ IDEA中如何實現熱部署
spring-boot-devtools是一個為開發(fā)者服務的一個模塊,其中最重要的功能就是自動應用代碼更改到最新的App上面去。,這篇文章主要介紹了SpringBoot項目在IntelliJ IDEA中如何實現熱部署,感興趣的小伙伴們可以參考一下2018-07-07Spring中的@Value和@PropertySource注解詳解
這篇文章主要介紹了Spring中的@Value和@PropertySource注解詳解,@PropertySource:讀取外部配置文件中的key-value保存到運行的環(huán)境變量中,本文提供了部分實現代碼,需要的朋友可以參考下2023-11-11java file.renameTo返回false的原因及解決方案
這篇文章主要介紹了java file.renameTo返回false的原因及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07關于Shiro過濾器配置方式(ShiroFilterFactoryBean)
這篇文章主要介紹了關于Shiro過濾器配置方式(ShiroFilterFactoryBean),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-12-12