javaGUI學習10:AWT-載入和顯示影象1
1、Image類與image包
Image抽象類,定義的方法提供對影象資訊的訪問。而建立和處理影象的基本機構則在image包裡。
- java.awt.Image的引用被傳遞給用來顯示和處理影象的其他AWT物件的方法,例如:drawImage(Image,int,int,ImageObserver):用來將圖片顯示在構件中。
- 在java.awt . image軟體包中,幾乎所有的類都和生產或消費影象有關。影象生產者為產生影象的位,而影象消費者接受影象的位。
- 在java.awt . image軟體包中,ImageProducer和 ImageConsumer介面都被實現兩次:畫素抓取器
- java . awt . Image類為影象提供引用,而java.awt . image軟體包實際從事與生產影象有關的工作。
Image方法:
void flush() //重新整理此Image物件使用的所有可重構資源。
float getAccelerationPriority() //返回加速優先順序提示的當前值。
ImageCapabilities getCapabilities(GraphicsConfiguration gc) //返回一個ImageCapabilities物件,可以在指定的GraphicsConfiguration上查詢此Image的功能。
abstract Graphics getGraphics() //建立用於繪製到螢幕外影象的圖形上下文。
abstract int getHeight(ImageObserver observer) //確定影象的高度。
abstract Object getProperty(String name, ImageObserver observer) //按名稱獲取此影象的屬性。
Image getScaledInstance(int width, int height, int hints) //建立此影象的縮放版本。
abstract ImageProducer getSource() //獲取生成影象畫素的物件。
abstract int getWidth(ImageObserver observer) //確定影象的寬度。
void setAccelerationPriority(float priority) //為此影象設定有關加速度有多重要的提示。
getWidth與getHeight返回的高度和寬度都是在影象完全被載入後才有效的
getSourse的意義是為了過濾該影象
影象都有一個與之關聯的Graphics,對影象進行畫面外緩衝
Graphics提供的過載的drawImage方法,可以將縮放後的影象畫出來
flush重新整理影象使用的所有資源,包括快取記憶體的影象畫素和系統資源,影象被完全重構的時,重新整理影象是一個必須的過程
2、影象的生產者與影象的消費者
AWT中,許多影象操作都是非同步進行的。例如,如果在呼叫的同時沒有載入影象,drawImage ()什麼也畫不出來,而只是產生與影象相關的位。
g.drawlmage ( image,o,o,this) ;
- 這麼做的作用僅僅只是不想讓你必須載入整個影象。
- 當影象生產者載入影象時,影象觀察者可以監視其進展情況。AWT構件就是一類影象觀察者,當它們發現影象被完全載入時,它們重繪製它們自身。所以呼叫drawImage ()暫存器中的 this構件作為觀察者。
- 當影象完全載入時,該構件被重繪製,paint ()方法被呼叫,再次呼叫drawlmage ()方法來繪製圖像中所有的位。
- 在AWT中,要想了解影象操作,要了解非同步以及ImageProducer和ImageObserver之間的關係。
2.1 ImageProducer
影象相關聯的位不在java.awt.Image中,但每個影象都維護一個和ImageProducer的關聯。
她的作用是生產影象的位並將他們傳遞給ImageConsumer。
影象生產者生產位。
2.2 ImageObserver
該介面中定義了一個常數集合和一個方法。
方法:
public voolean imageUpdate(Image img,int flags, int x, int y, int width, int height);
flags的作用是通知影象觀察者影象象生產的進展。下面的表中的常數代表傳遞給imageUpdate的flags引數中的位
標誌 | 含義 |
---|---|
ABORT | 影象載入被中斷 |
ALLBITS | 所有的位都已經載入給影象 |
ERROR | 在載入過程中發生錯誤 |
FRAMEBITS | 多幀影象的一個幀傳送,一般用於動畫GIF |
HEIGHT | 影象的高度已經可用 |
PROPERTIES | 影象的屬性已經可用 |
SOMEBITS | 影象的縮放變倜的多個位已可用 |
WIDTH | 影象的寬度已經可用 |
ImageObserver 的實現普遍存在於AWT中,這是因為java.awt.Component 實現 ImageObserver。所以,每個構件都是ImageObserver,當一個給定的 ImageProducer 採取非同步操作時,這個Ima-geObserver可以選擇是否被更新。
ps:所有的構件都是影象觀察者,所以任何構件都可以被傳遞到要獲取ImageObserver引數的方法中。
3、載入和顯示影象
import java.applet.Applet;
import java.awt.*;
import java.net.URL;
public class demo06 extends Applet {
Image image;
@Override
public void init() {
URL codeBase = getCodeBase();//這個applet位置的URL
System.out.println(codeBase);
image = getImage(codeBase,"1.jpg");//返回對影象的引用,為了闡明載入影象的非同步行為,影象的寬度和高度在getImage()返回後立即被顯示出來
System.Out.print(image.getWidth(this));
System.Out.print(image.getHeight(this));
}
public void paint(Graphics g){
g.drawImage(image,0,0,this);
}
}
顯示影象的寬度和高度都只是臨時值,儘管這時getImage已經返回對影象的引用,但定義影象的位還沒有被載入。Image相關的影象位在需要之前不被生產。所以在影象完全載入前,getWidth和getHeight都是-1。
4、非同步的影象載入和繪製
下面解釋上面程式現象的原因:
- 傳遞到Graphics.drawImage ()中的第三個引數指明瞭影象觀察者。在上面所舉的例子中,第三個引數是this,也就是說影象觀察者是this,這意味著觀察者是 applet自身。由於java.applet .Applet擴充套件了java.awt.Component,而且Component實現 ImageObserver,所以所有的 applet都具有真正的影象觀察者的資格。
- drawImage ()在第一次被呼叫時,沒有任何影象被載入。所以也就沒有影象位可繪製,drawImage ()僅僅向和影象相關的影象生產者註冊影象觀察者(在本例中,是applet自身)。所以當呼叫返回時,什麼也沒有繪製。
- 在呼叫drawImage ()返回之後,只要有影象的新的部分被載入,影象觀察者中的imageUpdate ()就會被呼叫。因為上面的 applet 程式範例中沒有覆蓋imageUpdate(),所以只要有新的影象位被載入,影象生產者就會呼叫通過繼承得到的Component . imageUpdate()。
- 當處理批量新載入的影象位時,Component.imageUpdate ()方法呼叫repaint (),結果是呼叫paint ()。當然,這個applet中的paint ()方法呼叫drawImage (),繪製和剛才得到影象位一樣多的影象。
上面所講的方法一直被迴圈呼叫,直到影象被完全載入:影象生產者載入影象的部分並呼叫影象觀察者中的imageUpdate ()。當影象觀察者是AWT構件時,Component . imageUpdate ()呼叫repaint ()方法清除構件背景並呼叫paint ()。在上面列舉出的程式範例中,applet 的 paint()呼叫drawImage ()方法繪製出剛剛得到的影象位。重複迴圈,影象生產者載入影象的下—塊,呼叫影象觀察者的imageUpdate ()。當影象被完全載入時,影象生產者停止呼叫觀察者imageUpdate (),迴圈中斷。
public void paint(Graphics g){
g.drawImage(image,0,0,this);
System.out.println(image.getWidth(this) + "後"); //載入完影象後,正確列印寬度
}
5、applet和應用程式的區別
applet 獲取影象提供內部支援,也就是Applet. getImage方法。而對於Java應用程式來講,沒有擴充套件applet,所以應用程式實現合併影象時,不同於 applet。
-
在ImageTestApplication構造器中,應用程式獲取影象的引用。應用程式從Toolkit類中呼叫getImage ()方法,而不是呼叫Applet . getImage ()方法。
-
首先,呼叫Toolkit類中的static getDefaultToolkit()方法,為返回應用程式執行的平臺預設的工具包。然後,呼叫工具包中的getImage方法,該方法返回java.awt. Image的引用。在這裡要注意的是 Toolkit.getImage()被過載,來獲取URL或String引數。
-
applet和應用程式之間的另一個區別是:應用程式的顯示位置必須被考慮。如果影象已經在(0,0)處被畫出,就像在程式範例5-1所給出的applet 程式碼一樣,影象的頂部將被繪製在框架標題條的下面。applet 的左上角位於applet選單條的下面,而應用程式的左上角則是位於其框架的頂端。
-
注意,addNotify ()被覆蓋以得到框架的空白區的引用,其目的是為了設定框架的邊框。在框架的同位體被建立之前,getInsets ()一直返回值為(0,0,0,0)的空白區。同位體由addNotify ()建立,所以呼叫getInsets ()方法必須在其框架對應的同位體被建立之後。請參見11.8節“構件和同位體”中的相關內容,可以得到更多的關於同位體和覆蓋addNotify ()的資訊。
-
最後,影象的尺寸大小是硬編碼進應用程式的,這種方法明確地不被推薦實行:
setBounds(100,100,217 + insets.left, 321 + insets.top);
6、等待影象載入
所有的applet程式和應用程式實現載入和顯示影象都是採用從影象的頂部到底部的方式進行的,這是由於影象載入的非同步所導致的。一個比較美觀、令人滿意的方法是在影象顯示之前等待影象完全載入。有很多的途徑可以用來實現該效果,其中的一個途徑就是使用imageUpdate()方法,使用該方法可以獲得載入影象的進展狀況。
7、一次繪製圖像的一行掃描線
重寫imageUpdate()方法,在imageUpdate()中呼叫repaint()方法
@Override
public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, int h) {
System.out.println(h);
repaint();
if((infoflags & ALLBITS) == 0) {
return true;
}else {
return false;
}
}
但這樣會引起閃動,消除閃動:重寫update方法。因為呼叫repaint(),update()會被觸發呼叫,但在預設模式下update會先清除構件中所有的背景,在呼叫構件中的paint方法。
public void update(Graphics g){
paint(g);
}
8、MediaTracker
與影象的非同步載入相比,這個類提供了一個比較方便的方法,可以跟蹤影象的載入。
使用MediaTracker分為下面的三步:
1)建立MediaTracker例項。
2)使用 MediaTracker . addImage ()指明要跟蹤的影象物件。
3)建立try/catch 塊。try 塊等待和ID相關的影象完全載入。
由於MediaTracker 的 waitForID方法可能丟擲InterruptedException,所以實現catch塊是必要的。
如果你希望在顯示影象之前,先將影象完全載入,可以使用MediaTracker。使用MediaTracker意味著你不必覆蓋imageUpdate ()方法,而且不必通過將變數flags和正確的常量求與來判斷什麼時候影象被完全載入。
public static void waitForImage(Component component, Image image){
MediaTrachker tracker = new Mediatracker(component);
tracker.addImage(image,0);
tracker.waitForID(0);
}