版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、第10章 Java I/O本章學(xué)習(xí)目標(biāo)理解流的概念。掌握InputStream和OutputStream及派生類。掌握Reader和Writer及其派生字符流類。掌握File類和RandomAccessFile類的應(yīng)用。了解java.io包的包裝技術(shù)和設(shè)計(jì)思想。I/O計(jì)算機(jī)程序的最一般模型其實(shí)可以歸納為:輸入、計(jì)算和輸出。輸入和輸出是人機(jī)交互的重要手段,一個(gè)設(shè)計(jì)合理的程序應(yīng)該首先允許用戶根據(jù)具體情況輸入不同的數(shù)據(jù),然后經(jīng)過程序算法的計(jì)算處理,最后以用戶容易接受的方式輸出結(jié)果。 10.2 流的概念 流(Stream)是對數(shù)據(jù)傳送的一種抽象,當(dāng)預(yù)處理數(shù)據(jù)從外界“流入”程序中,就稱之為輸入流,相反,
2、當(dāng)程序中的結(jié)果數(shù)據(jù)“流到”外界(如顯示屏幕、文件等)時(shí),就稱之為輸出流輸入或輸出其實(shí)是從程序角度來看待的。在Java類庫中,I/O(輸入和輸出)部分的內(nèi)容不少,這點(diǎn)看看JDK的java.io包就知道了,它涉及的主要關(guān)鍵類有:InputStream、OutputStream、Reader、Writer和File等。 Java I/O類InputStream和OutputStream類是用來處理字節(jié)(8位)流的。Reader和Writer類用來處理字符(16位)流。File類則用來處理文件。 標(biāo)準(zhǔn)輸出 System.out是標(biāo)準(zhǔn)輸出流對象,可以通過調(diào)用它的println()、print()或wri
3、te()方法來實(shí)現(xiàn)對各種數(shù)據(jù)的輸出顯示。 【例 10-1】標(biāo)準(zhǔn)輸出方法舉例。 標(biāo)準(zhǔn)輸入 System.in是標(biāo)準(zhǔn)輸入流對象,可以通過調(diào)用它的read()方法來實(shí)現(xiàn)從鍵盤讀入數(shù)據(jù)的功能。由于輸入比輸出容易出錯(cuò),Java對輸入操作強(qiáng)制設(shè)置了異常保護(hù),程序中必須拋出異常或捕獲異常,否則程序?qū)⒉荒芫幾g通過。 【例 10-2】標(biāo)準(zhǔn)輸入方法舉例。Hint對于多數(shù)程序設(shè)計(jì)語言(如C和Pascal)來說,它處理的一般字符都是單字節(jié)的,而對于Java來說,情況比較特別,當(dāng)用戶輸入一般字符(此時(shí)為單字節(jié))給Java程序后,若程序中用來存放該字符的數(shù)據(jù)類型為char時(shí),原本的單字節(jié)會自動在高位補(bǔ)擴(kuò)充為雙字節(jié)進(jìn)行存儲
4、。Java采用雙字節(jié)存儲原本為單字節(jié)的一般字符,主要是為了將一般字符與其他字符(如漢字字符)統(tǒng)一起來,方便處理。后面介紹的(Unicode)字符流,即指雙字節(jié)流。 標(biāo)準(zhǔn)輸入功能擴(kuò)充 原本System.in標(biāo)準(zhǔn)輸入流對象只能提供以字節(jié)為單位的數(shù)據(jù)輸入,通過引入InputStreamReader和BufferedReader類的對象對其進(jìn)行兩次包裝(第一次將System.in對象包裝為reader對象的內(nèi)嵌成員,第二次又將reader對象包裝為input對象的成員),這樣,就可以使用BufferedReader類提供的readLine()方法,實(shí)現(xiàn)以行為單位的字符串輸入功能。當(dāng)獲取字符串?dāng)?shù)據(jù)后,還
5、可以根據(jù)具體的數(shù)據(jù)類型進(jìn)行相應(yīng)轉(zhuǎn)換。 【例 10-3】擴(kuò)充的標(biāo)準(zhǔn)輸入方法。 【例 10-4】用戶輸入類MyInput。 【例 10-5】測試MyInput用戶輸入類。為了避免不同地方需要進(jìn)行交互式輸入時(shí)每次都要重新編寫包裝語句,建議讀者:將上述常用交互式輸入單獨(dú)定義為一個(gè)用戶輸入類MyInput,并將其放置到用戶自定義類包myPackage中,以后各個(gè)程序或者程序的不同地方就可以方便地進(jìn)行交互式輸入了。 10.3 字節(jié)流 以字節(jié)為處理單位的流稱為字節(jié)流,字節(jié)流相應(yīng)地分為字節(jié)輸入流和字節(jié)輸出流兩種。 InputStream 所有字節(jié)輸入流的基類為InputStream,它是一個(gè)從Object類直
6、接繼承而來的抽象類,類中聲明有多個(gè)用于字節(jié)輸入的方法,為其他字節(jié)輸入流派生類奠定了一個(gè)基礎(chǔ),它與其他派生類的繼承關(guān)系如下圖所示 :ByteArrayInputStream ByteArrayInputStream輸入流類含有四個(gè)成員變量:buf 、count、 mark和 pos。buf為字節(jié)數(shù)組緩沖區(qū),用來存放輸入流;count為計(jì)數(shù)器,記錄輸入流數(shù)據(jù)的字節(jié)數(shù);mark用來做標(biāo)記,以實(shí)現(xiàn)重讀部分輸入流數(shù)據(jù);pos為位置指示器,指明當(dāng)前讀指針的位置,即已讀取count-1個(gè)字節(jié)的數(shù)據(jù)。ByteArrayInputStream輸入流類提供的方法基本上與它的基類InputStream是一樣的,因此
7、,ByteArrayInputStream可以說是一個(gè)比較簡單和基礎(chǔ)的字節(jié)輸入流類。 FileInputStream FileInputStream類是用來實(shí)現(xiàn)從文件中讀取字節(jié)流數(shù)據(jù)的,它也是從抽象類InputStream直接繼承而來,不過,有些方法,如mark()和reset()等,它并不支持,因?yàn)镕ileInputStream輸入流只能實(shí)現(xiàn)文件的順序讀取。另外,F(xiàn)ileInputStream既然屬于字節(jié)輸入流類,那么它就不適合來讀取字符文件,而適合讀取字節(jié)文件(如圖像文件)。字符文件的讀取可以采用后面要介紹的字符輸入流類FileReader?!纠?10-6】測試FileInputStrea
8、m文件輸入流類。import java.io.*;public class TestFileInputStream public static void main(String args) throws IOExceptiontry /創(chuàng)建文件輸入流對象fisFileInputStream fis = new FileInputStream(data.dat);byte buf = new byte128;int count; /記錄實(shí)際讀取字節(jié)數(shù)count=fis.read(buf); /從文件輸入流fis中讀取字節(jié)數(shù)據(jù)System.out.println(共讀取+count+個(gè)字節(jié));Sy
9、stem.out.print(new String(buf);fis.close(); /關(guān)閉fis輸入流catch (IOException ioe)System.out.println(I/O異常);FilterInputStream FilterInputStream是為了包裝InputStream流而引入的中間類,說它是中間類,是因?yàn)樗臉?gòu)造方法的訪問屬性為protected的,即用戶不能直接將其實(shí)例化,創(chuàng)建FilterInputStream對象,它把具體的包裝任務(wù)交給了它的子類們來完成。這些子類有BufferedInputStream、CheckedInputStream、DataI
10、nputStream、 LineNumberInputStream等,每一個(gè)子類都是以現(xiàn)成的InputStream流對象為其數(shù)據(jù)源,試圖對該InputStream流做進(jìn)一步的處理。當(dāng)然,有興趣的讀者也可以試著自己定義一個(gè)從FilterInputStream繼承而來的加強(qiáng)輸入流類,實(shí)現(xiàn)對輸入流的特殊處理(如按位讀取等)。 BufferedInputStream BufferedInputStream類只是在FilterInputStream類(或者說InputStream類)的基礎(chǔ)上添加了一個(gè)讀取緩沖功能,因此,也有人說它本來應(yīng)該合并到InputStream中去才對。不過,我們更關(guān)心的是,到底緩
11、沖能帶來多大的性能提高呢?例10-7就是一個(gè)測試程序,讀者有興趣的話可以親自上機(jī)驗(yàn)證一下,我們在自己的計(jì)算機(jī)上對輸入流的緩沖與否做了一個(gè)測試,測試讀取的為一圖片文件,大小約為2.52M,結(jié)果表明,它們二者之間的速度差別還是非常明顯的,對于小輸入流的讀取況且如此,那么對于大輸入流情況,則緩沖帶來的效果就可想而知了。 【例 10-7】測試BufferedInputStream輸入流類帶來的性能提高。import java.io.*;public class TestBufferedInputStream public static void main(String args) throws IOE
12、xception try /創(chuàng)建文件輸入流對象fis,為了取得明顯效果,Big.dat文件中編輯了大量數(shù)據(jù) InputStream fis =new BufferedInputStream( new FileInputStream(Big.dat); System.out.println(測試開始.); while (fis.read()!=-1) /從文件輸入流fis中讀取字節(jié)數(shù)據(jù) /讀取整個(gè)文件輸入流 System.out.println(測試結(jié)束); fis.close(); /關(guān)閉fis輸入流 catch (IOException ioe)System.out.println(I/O異
13、常); OutputStream 抽象類OutputStream是所有字節(jié)輸出流類的基類,它的派生關(guān)系如下圖所示: FileOutputStream 【例 10-8】FileOutputStream文件輸出流類。import java.io.*;public class TestFileOutputStream public static void main(String args)try System.out.print(請輸入數(shù)據(jù): ); int count,n=128; byte buffer = new byten; count = System.in.read(buffer); /讀
14、取標(biāo)準(zhǔn)輸入流 FileOutputStream fos = new FileOutputStream(test.dat); /創(chuàng)建文件輸出流對象 fos.write(buffer,0,count); /寫入輸出流 fos.close(); /關(guān)閉輸出流 System.out.println(已將上述輸入數(shù)據(jù)輸出保存為test.dat文件。);catch (IOException ioe) System.out.println(ioe); catch (Exception e) System.out.println(e); 10.4 字符流 字符流類是為方便處理16位Unicode字符而(在JD
15、K1.1之后)引入的輸入輸出流類,它以兩個(gè)字節(jié)為基本輸入輸出單位,適合于處理文本類型數(shù)據(jù)。Java設(shè)計(jì)的字符流體系中有兩個(gè)基本類:Reader和Writer,分別對應(yīng)字符輸入流和字符輸出流。 10.4.1 ReaderReader字符輸入流是一個(gè)抽象類,本身不能被實(shí)例化,因此真正實(shí)現(xiàn)字符流輸入功能的是由它派生的子類們,如BufferedReader、CharArrayReader、FilterReader、InputStreamReader、PipedReader和StringReader等,其中一些子類又再進(jìn)一步派生出其他功能子類,其繼承關(guān)系如下圖所示: 特色Java輸入輸出的一個(gè)特色就是可
16、以組成使用(包裝)各種輸入輸出流為功能更強(qiáng)的流,因此,才設(shè)計(jì)定義了這么多各具功能的輸入輸出流類。下面請看一個(gè)程序例子。 【例 10-9】FileReader和BufferedReader的組合使用。 import java.io.*; public class TestFileReader public static void main(String args) try FileReader fr = new FileReader(fuwa.dat); BufferedReader bfr = new BufferedReader(fr); String str=bfr.readLine();
17、 while (str!=null) System.out.println(str); str=bfr.readLine(); catch (IOException ioe)System.out.println(ioe);catch (Exception e)System.out.println(e); 10.4.2 Writer字符流輸出基類Writer也是一個(gè)抽象類,本身不能被實(shí)例化,因此真正實(shí)現(xiàn)字符流輸出功能的是由它派生的子類們,如BufferedWriter、CharArrayWriter、FilterWriter、 OutputStreamWriter、PipedWriter、Pri
18、ntWriter和StringWriter等,其中OutputStreamWriter子類又再進(jìn)一步派生出FileWriter子類,其繼承關(guān)系如下圖所示: FileWriter類的其他方法都是從它的父類繼承而來的。在實(shí)際應(yīng)用中,常將FileWriter類的對象包裝為BufferedWriter對象,以提高字符輸出效率。請看下面的例子。 【例 10-10】FileWriter和BufferedWriter的組合使用。 import java.io.*; public class TestFileWriter public static void main(String args) try Inp
19、utStreamReader isr = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(isr); FileWriter fw = new FileWriter(out.dat); BufferedWriter bw = new BufferedWriter(fw); String str = br.readLine(); while(!(str.equals(#) bw.write(str,0,str.length(); bw.newLine(); str = br.readLine(); b
20、r.close(); bw.close(); catch(IOException e) e.printStackTrace(); 注意bw.newLine();語句在不同系統(tǒng)下實(shí)際輸出的行分隔符是不同的,在Windows下是“r”(回車)和“n”(換行),在Unix/Linux下只有“n”,而在Mac OS下則是“r”,因此,如果在Windows下用記事本程序打開Unix/Linux下編輯的文本文件,就會看不到分行的效果,要想恢復(fù)原來的分行效果,可以通過將每一個(gè)“n”轉(zhuǎn)換為“r”和“n”,這樣,就可以恢復(fù)Unix/Linux下分行的效果了。下面請看實(shí)現(xiàn)這一轉(zhuǎn)換過程的一個(gè)程序示例。 【例 10-
21、11】Unix文本文件轉(zhuǎn)換為Windows文本文件。import java.io.*;public class Unix_2_Win public static void main(String args) try FileReader fileReader = new FileReader(unix.dat); FileWriter fileWriter = new FileWriter(win.dat); char line = r, n; int ch = fileReader.read(); while(ch != -1) /直到文件結(jié)束 if(ch = n) fileWriter.w
22、rite(line); /實(shí)施轉(zhuǎn)換 else fileWriter.write(ch); /不變 ch = fileReader.read(); /讀取下一個(gè)字符 fileReader.close(); /關(guān)閉輸入流 fileWriter.close(); /關(guān)閉輸出流 catch(IOException e) e.printStackTrace(); Unix下編輯的文本文件unix.dat在Windows下用記事本打開,如下圖所示: 當(dāng)執(zhí)行上述程序,對Unix.dat文件進(jìn)行讀取并轉(zhuǎn)換保存為win.dat后,再用記事本打開,顯示效果如下圖所示: PipedWriter PipedWrite
23、r為管道字符輸出流類,它必須與相應(yīng)的PipedReader一起工作,共同實(shí)現(xiàn)管道式輸入輸出。 10.5 文件10.5.1 File類與java.io包定義的其他輸入輸出類不同的是,F(xiàn)ile類直接處理文件和文件系統(tǒng)本身,也就是說File類并不關(guān)心怎樣從文件讀取數(shù)據(jù)流或向文件存儲數(shù)據(jù)流,它主要用來描述文件或目錄的自身屬性。通過創(chuàng)建File類對象,我們可以處理和獲取與文件相關(guān)的信息,比如文件名、相對路徑、絕對路徑、上級目錄、是否存在、是否是目錄、可讀、可寫、上次修改時(shí)間和文件長度等。此外,當(dāng)File對象為目錄時(shí),還可以列舉出它的文件和子目錄。一個(gè)File類對象被創(chuàng)建后,它的內(nèi)容就不能再改變了,要想改
24、變(即進(jìn)行文件讀寫操作)就必須利用前面介紹過的強(qiáng)大I/O流類對其進(jìn)行包裝或者使用后面即將介紹的RandomAccessFile類??傊?,對于Java語言,不管是文件還是目錄都用File類來表示。 【例 10-13】File類示例程序。import java.io.*;import java.util.*;public class TestFile public static void main(String args) try File f = new File(args0); if(f.isFile() / 是否是文件 System.out.println(該文件屬性如下所示:); Syst
25、em.out.println(文件名- +f.getName(); System.out.println(f.isHidden()? -隱藏 : -沒隱藏); System.out.println(f.canRead() ? -可讀 : -不可讀 ); System.out.println(f.canWrite() ? -可寫 : -不可寫 ); System.out.println(大小- +f.length() + 字節(jié)); System.out.println(最后修改時(shí)間- +new Date(f.lastModified(); else / 列出所有的文件和子目錄 File fs =
26、 f.listFiles(); ArrayList fileList = new ArrayList(); for(int i = 0; i fs.length; i+) / 先列出文件 if(fsi.isFile() /是否是文件 System.out.println( +fsi.getName(); else / 子目錄存入fileList,后面再列出 fileList.add(fsi); / 列出子目錄 for(int i=0;ifileList.size();i+) f = (File)fileList.get(i); System.out.println( +f.getName();
27、 System.out.println(); catch(ArrayIndexOutOfBoundsException e) System.out.println(e.toString(); 10.5.2 RandomAccessFile類上述File類不能進(jìn)行文件讀寫操作,必須通過其他類來提供該功能,RandomAccessFile類就是其中之一。RandomAccessFile類與前面介紹過的文件輸入輸出流類相比,其文件存取方式更靈活,它支持文件的隨機(jī)存?。≧andom Access):在文件中可以任意移動讀取位置。RandomAccessFile類對象可以使用seek()方法來移動文件存
28、取的位置,移動單位為字節(jié),為了能正確移動存取位置,編程者必須清楚隨機(jī)存取文件中各數(shù)據(jù)的長度和組織。 【例 10-14】RandomAccessFile類示例程序。import java.io.*;import java.util.*;import myPackage.MyInput;/定義圖書類Bookclass Book private StringBuffer name; private short price; /2個(gè)字節(jié) public Book(String n,int p) name=new StringBuffer(n); name.setLength(7); /限定為固定的7個(gè)字
29、符(14字節(jié)) price=(short)p; public String getName() return name.toString(); public short getPrice() return price; public static int size() return 16; public class TestRandomAccessFile public static void main(String args) throws IOException Book books = new Book(Java教程, 22),new Book(操作系統(tǒng), 38), new Book(編
30、譯原理, 29),new Book(計(jì)算機(jī)網(wǎng)絡(luò), 32), new Book(計(jì)算機(jī)圖形學(xué), 18),new Book(數(shù)據(jù)庫原理, 12); File f = new File(stock.dat); /以讀寫方式打開stock.dat文件 RandomAccessFile raf = new RandomAccessFile(f, rw); /將books中的書本信息寫入文件 for(int i = 0; i books.length; i+) raf.writeChars(booksi.getName(); raf.writeShort(booksi.getPrice(); System
31、.out.print(查詢第幾本書?); /利用自定義類MyInput進(jìn)行數(shù)據(jù)輸入 int n = MyIData(); /通過seek()定位到第n本書的數(shù)據(jù)起始位置 raf.seek(n-1) * Book.size(); /bname用于存放讀取到的第n本書的書名 char bname=new char7; char ch; for(int i=0;i7;i+) ch = raf.readChar(); if (ch=0) bnamei=0; else bnamei=ch; System.out.print(書名:); System.out.println(bname); System.
32、out.println(單價(jià): + raf.readShort(); /輸出讀取到的第n本書的單價(jià) raf.close(); /關(guān)閉文件 提示所有文件都是二進(jìn)制文件,至于文件中的二進(jìn)制數(shù)據(jù)如何解讀?這完全取決于它的數(shù)據(jù)組織方式和編碼格式??傊幋a(以及相應(yīng)的解碼)是計(jì)算機(jī)之所以能用簡單的0、1來表達(dá)整個(gè)世界的關(guān)鍵!文件讀寫操作三步驟一般進(jìn)行文件讀寫操作應(yīng)包括如下三個(gè)步驟: 1、以某種讀寫方式打開文件; 2、進(jìn)行文件讀寫操作; 3、關(guān)閉文件。需要特別注意的是:對于某些文件存取對象來說,關(guān)閉文件的動作就意味著將緩沖區(qū)(Buffer)中的數(shù)據(jù)全部寫入磁盤文件,如果不進(jìn)行(或忘記)文件關(guān)閉操作,某些
33、數(shù)據(jù)可能就會因?yàn)闆]能及時(shí)寫入文件而發(fā)生丟失。10.6 小結(jié)計(jì)算機(jī)程序的執(zhí)行往往涉及到數(shù)據(jù)輸入和輸出,因此,幾乎每一種程序設(shè)計(jì)語言都提供了相應(yīng)的輸入輸出功能。本章結(jié)合Java語言提供的輸入輸出包java.io對各種輸入輸出功能作了介紹,包括流的概念、字節(jié)流、字符流以及一些常見的文件操作等。另外,需要指出的是:java.io包給開發(fā)者提供強(qiáng)大輸入輸出功能的同時(shí),本身也展示了各種面向?qū)ο蠹夹g(shù),值得廣大開發(fā)人員去模仿和借鑒。 作業(yè)1257812第11章 Java游戲開發(fā)基礎(chǔ)本章學(xué)習(xí)目標(biāo)理解java 2D圖形圖像繪制方法。理解圖形圖像坐標(biāo)變換的技術(shù)。掌握動畫生成技術(shù)。掌握動畫閃爍消除技術(shù)。11.1 概述
34、Java是一種具有豐富功能的編程語言,它的跨平臺性、安全性、健壯性、支持分布式網(wǎng)絡(luò)應(yīng)用、以及面向?qū)ο筇匦远挤浅_m合游戲開發(fā)。 Java有兩種不同類型的程序,一種是在計(jì)算機(jī)上獨(dú)立運(yùn)行的Java應(yīng)用程序(Java application),另一種是在瀏覽器里面運(yùn)行的Java小應(yīng)用程序(Java applet)。兩種程序都可以用于游戲開發(fā),基本技術(shù)和和思想是一致的。 11.2 繪制2D圖形圖像 一款游戲能否激起人們的興趣并在游戲上付出時(shí)間,游戲的畫面是否吸引人是關(guān)鍵因素之一 。 Java提供了豐富的類庫來幫助繪制合適的文本和圖形圖像,這些類庫多數(shù)都包含在了java.awt、java.awt.imag
35、e、java.awt.geom和javax包中。 11.2.1 坐標(biāo)體系 顯示器由許多微小的像素組成,每個(gè)像素就是一個(gè)帶有顏色的光點(diǎn),屏幕水平和垂直方向的像素?cái)?shù)就稱為屏幕的分辨率。 把屏幕的左上角當(dāng)做坐標(biāo)原點(diǎn),并把向右向下當(dāng)做坐標(biāo)的正向增長。位置坐標(biāo)可以用(x, y)表示,其中x表示水平方向距離原點(diǎn)的像素?cái)?shù),y表示垂直方向距離原點(diǎn)的像素?cái)?shù) 。Java的一些容器組件,比如Window、Panel、Frame、JFrame、Applet,在其上繪制文本與圖形圖像時(shí)用到的位置坐標(biāo),也是以組件的左上角為原點(diǎn),以像素為長度單位 。 11.2.1 坐標(biāo)體系 11.2.2 繪制圖形 java中通過java.
36、awt包中的Graphics類繪制圖形圖像,這個(gè)工具在繪圖時(shí)存在一定的局限性,比如不能旋轉(zhuǎn)圖形 。 在java SE 1.2版本中引入了java 2D類庫,這些類庫基本都包含在java.awt包和java.awt.geom包中 ,比如Point2D、Line2D、Rectangle2D、Ellipse2D 。想要繪制這些圖形必須通過Graphics2D類的對象,Graphics2D是Graphics類的子類,F(xiàn)rame、Applet等的paint或paintComponent方法自動接收到Graphics2D類的對象 。 11.2.2 繪制圖形 在需要Graphics2D類的方法時(shí),直接類型轉(zhuǎn)
37、換為Graphics2D類型即可: paint(Graphics g) Graphics2D g2d = (Graphics2D)g; g2d.xxxx();11.2.2 繪制圖形 Graphics2D對象的draw和fill方法繪制圖形和填充圖形,兩個(gè)方法都以Shape接口類型作為參數(shù),根據(jù)java的多態(tài)特性,任何一個(gè)實(shí)現(xiàn)了Shape接口的類型都可以作為draw和fill的參數(shù),例如:Rectangle2D rectangle = new .;g2d.draw(rectangle);11.2.2 繪制圖形 java 2D類庫為圖形類提供了兩個(gè)版本,一個(gè)具有float類型坐標(biāo),一個(gè)具有doub
38、le類型坐標(biāo)。比如Rectangle2D類,只是一個(gè)抽象類,它具有兩個(gè)靜態(tài)內(nèi)部子類:Rectangle.Float、Rectangle.Double。創(chuàng)建單精度和雙精度坐標(biāo)的矩形時(shí)可以提供矩形左上角水平和垂直坐標(biāo)以及矩形的寬度和高度:11.2.2 繪制圖形 Rectangle2D rectf = new Rectangle2D.Float(40, 60, 200, 100);g2d.draw(rectf); Rectangle2D rectd = new Rectangle2D.Double(40, 180, 200, 100); g2d.draw(rectd); 11.2.2 繪制圖形 【例
39、11-1】DrawShapeTest.java【例11-1】DrawShapeTest.javapublic class DrawShapeTest extends JFrame public void paint(Graphics g) Graphics2D g2d = (Graphics2D)g; Rectangle2D rect = new Rectangle2D.Double(40, 60, 200, 100); g2d.draw(rect); Line2D line = new Line2D.Double(40, 60, 240, 160); g2d.draw(line); Elli
40、pse2D ellipse = new Ellipse2D.Double(40, 60, 200, 100); g2d.draw(ellipse);11.2.3 繪制圖像 有三種方式將圖像讀取到程序中,讀取之后通過Graphics2D的drawImage()方法將圖像繪制到屏幕窗口中 。 第一種方式,借助于java.awt包中Tookit類的getImage()方法,它返回Image類型的對象,Image對象里面包含了圖像數(shù)據(jù)和圖像的寬度、高度等信息,使用Toolkit類讀取圖像的一般方式為:11.2.3 繪制圖像 String filename = “”; Toolkit tk = Tool
41、kit.getDefaultToolkit(); Image image = tk.getImage(filename); while(image.getWidth(observer) = 0); 循環(huán)是為了等待圖像被完整讀取 。11.2.3 繪制圖像 第二種方式,借助于javax.swing包中ImageIcon類的getImage()方法,它也是返回Image類型的對象,并且等待圖像完全讀取之后返回,使用ImageIcon類讀取圖像的一般方式為: String filename = “”; ImageIcon icon = new ImageIcon(filename); Image im
42、age = icon.getImage();11.2.3 繪制圖像 第三種方式,借助于javax.imageio包中的ImageIO類的read()方法,它仍是返回Image類型的對象,并且等待圖像完全讀取之后返回: String filename = “”; Image image = ImageIO.read(new File(filename); 或者提供文件的URL: String urlname = “”; Image image = ImageIO.read(new URL(url);11.2.3 繪制圖像 boolean drawImage(Image img, int x, i
43、nt y, ImageObserver observer)顯示未經(jīng)縮放的圖像,方法有可能在圖像繪制完成前返回;參數(shù):img 被顯示的圖像 x 圖像左上角的x坐標(biāo) y 圖像左上角的y坐標(biāo) observer 更新圖像信息的對象,可以是null11.2.3 繪制圖像 boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer)顯示縮放過的圖像,在寬為width、高為height的區(qū)域縮放圖像;參數(shù):img 被顯示的圖像 x 圖像左上角的x坐標(biāo) y 圖像左上角的y坐標(biāo) width 縮放
44、后的圖像的寬度 height 縮放后的圖像的高度 observer 更新圖像信息的對象,可以是null 11.2.3 繪制圖像 【例11-2】DrawImageTest.java11.3 圖形圖像的坐標(biāo)變換 在游戲編程中,經(jīng)常需要將游戲元素進(jìn)行平移、尺度縮放、角度旋轉(zhuǎn)和變形等操作,這就要對java圖形環(huán)境進(jìn)行坐標(biāo)變換,Graphics2D類和AffineTransform類的幾個(gè)方法實(shí)現(xiàn)了坐標(biāo)變換功能。11.3.1 使用Graphics2D類進(jìn)行坐標(biāo)變換 平移 Graphics2D類的translate()方法實(shí)現(xiàn)了對Graphics2D坐標(biāo)系的平移變換: g2d.translate(x, y
45、); g2d.draw(.);這個(gè)方法的作用是把Graphics2D坐標(biāo)系的原點(diǎn)移動到當(dāng)前坐標(biāo)系的(x, y)之處,其后繪制圖形圖像時(shí)所使用的坐標(biāo)將以新坐標(biāo)系為基準(zhǔn),以原坐標(biāo)系的(x, y)之處作為新原點(diǎn),繪制的結(jié)果相當(dāng)于將圖形圖像進(jìn)行了平移 11.3.1 使用Graphics2D類進(jìn)行坐標(biāo)變換 尺度縮放Graphics2D類的scale()方法實(shí)現(xiàn)了對坐標(biāo)系的尺度縮放功能,scale()方法的使用方式為:g2d.scale(sx, sy);g2d.draw(.);sx、sy是雙精度(double)類型,是將當(dāng)前坐標(biāo)系的坐標(biāo)進(jìn)行縮放的縮放因子,縮放后:xnew = x*sx,ynew = y*
46、sy。該方法執(zhí)行之后繪制圖形圖像時(shí)所用的坐標(biāo)將以縮放后的新坐標(biāo)系為基準(zhǔn),繪制的結(jié)果相當(dāng)于將圖形圖像進(jìn)行了縮放,縮放因子為sx、sy。11.3.1 使用Graphics2D類進(jìn)行坐標(biāo)變換 角度旋轉(zhuǎn)Graphics2D類的rotate()方法實(shí)現(xiàn)了對Graphics2D坐標(biāo)系的角度旋轉(zhuǎn)功能:g2d.rotate(angle);g2d.draw(.);參數(shù)angle以弧度為單位,表示將當(dāng)前坐標(biāo)系以原點(diǎn)為中心旋轉(zhuǎn)angle弧度,如果angle為正值,將從x軸正方向向y軸正方向旋轉(zhuǎn),如果angle為負(fù)值,將從x軸正方向向y軸負(fù)方向旋轉(zhuǎn)。11.3.1 使用Graphics2D類進(jìn)行坐標(biāo)變換 角度旋轉(zhuǎn)rot
47、ate()方法的第二種使用方式為:g2d.rotate(angle, x, y);g2d.draw(.);帶參數(shù)x、y的rotate()方法相當(dāng)于如下順序的三個(gè)方法調(diào)用:translate(x, y);rotate(angle);translate(-x, -y);11.3.1 使用Graphics2D類進(jìn)行坐標(biāo)變換 Graphics2D的若干坐標(biāo)變換方法的順序調(diào)用組成了一個(gè)變換組合,作用的順序與方法調(diào)用的順序一致。上述第一個(gè)方法調(diào)用對坐標(biāo)系進(jìn)行平移變換,將坐標(biāo)原點(diǎn)平移到(x, y)處,第二個(gè)對平移后的新坐標(biāo)系進(jìn)行旋轉(zhuǎn)angle弧度的變換,第三個(gè)再對旋轉(zhuǎn)后的坐標(biāo)系進(jìn)行平移,將原點(diǎn)移動到當(dāng)前坐標(biāo)
48、系的(-x, -y)之處??傮w結(jié)果,相當(dāng)于圍繞(x, y)旋轉(zhuǎn)了angle弧度。11.3.1 使用Graphics2D類進(jìn)行坐標(biāo)變換 所以,如果想讓圖形圖像在某位置(sitex, sitey)圍繞自己的中心(sitex+width/2, sitey+height/2)進(jìn)行旋轉(zhuǎn),需要調(diào)用:rotate(angle, sitex+width/2, sitey+height/2 );或下列組合調(diào)用:translate(sitex+width/2, sitey+height/2);rotate(angle);translate(-sitex-width/2, -sitey-height/2);11.3
49、.1 使用Graphics2D類進(jìn)行坐標(biāo)變換 【例11-3】TransformTest.java11.3.2 使用AffineTransform類進(jìn)行坐標(biāo)變換 平移、尺度縮放、角度旋轉(zhuǎn)和變形等坐標(biāo)變換,可以用矩陣變換來表示:平移、尺度縮放、角度旋轉(zhuǎn)和變形等坐標(biāo)變換,可以用矩陣變換來表示:其中a、b、c、d、e、f等變量取適當(dāng)?shù)闹担湍軐?shí)現(xiàn)坐標(biāo)系的平移、尺度縮放、角度旋轉(zhuǎn)和變形等變換,這類變換一般稱為仿射變換。11.3.2 使用AffineTransform類進(jìn)行坐標(biāo)變換 java.awt.geom包中的AffineTransform類提供了仿射變換的功能,如果知道某種坐標(biāo)變換對應(yīng)的變換矩陣,可
50、以通過以下方式直接創(chuàng)建具有特定坐標(biāo)變換功能的AffineTransform對象:AffineTransform transform = new AffineTransform(a, b, c, d, e, f);11.3.2 使用AffineTransform類進(jìn)行坐標(biāo)變換 如果不清楚坐標(biāo)變換到底對應(yīng)哪一個(gè)變換矩陣,可以直接調(diào)用AffineTransform類的getTranslateInstance()、getRotateInstance()、getScaleInstance()和getShearInstance()方法來創(chuàng)建具有相應(yīng)坐標(biāo)變換功能的AffineTransform對象。比如:A
51、ffineTransform transform = AffineTransform.getScaleInstance(2, 2);返回一個(gè)對應(yīng)下列伸縮變換矩陣的AffineTransform對象: 11.3.2 使用AffineTransform類進(jìn)行坐標(biāo)變換 另外,AffineTransform的setToRotation()、setToScale()、 setToTranslation()和setToShear()方法將一個(gè)AffineTransform對象設(shè)置為具有其它相應(yīng)變換功能的對象,例如:transform.setToRotation(angle);將transform對象設(shè)置為
52、具有旋轉(zhuǎn)功能的對象。11.3.2 使用AffineTransform類進(jìn)行坐標(biāo)變換 設(shè)置好AffineTransform對象,要讓它發(fā)揮坐標(biāo)變換的作用,一般采用下列方式:AffineTransform transform = ;g2d.drawImage(shap, transform, observer);使用帶有AffineTransform對象參數(shù)的drawImage方法時(shí)不再指明圖形圖像的位置坐標(biāo),默認(rèn)會在變換后的坐標(biāo)系原點(diǎn)處繪制圖形圖像。11.3.2 使用AffineTransform類進(jìn)行坐標(biāo)變換 利用Graphics2D的translate()、rotate()等方法可以實(shí)現(xiàn)坐標(biāo)
53、變換,現(xiàn)在,利用Graphics2D的setTransform()可以將Graphics2D對象的坐標(biāo)變換設(shè)置為AffineTransform對象的坐標(biāo)變換,方式為:g2d.setTransform(transform);g2d.draw(); 這時(shí)draw的參數(shù)里面不再需要transform對象。11.3.2 使用AffineTransform類進(jìn)行坐標(biāo)變換 可以通過AffineTransform類的translate()、scale()和rotate()等方法對變換進(jìn)行組合,它們的參數(shù)、使用方式、變換組合方式和Graphics2D類的對應(yīng)方法是一致的。例11-4演示了AffineTrans
54、form的translate()、scale()和rotate()等方法的使用方式:11.4 生成動畫 一系列動作連續(xù)的圖片,在屏幕上連續(xù)繪制它們會產(chǎn)生動畫效果,其中每一幅圖片稱為一幀。這些連續(xù)圖片可以是獨(dú)立的圖片文件,也可以所有幀存放到一個(gè)圖片文件里面。如果每一幀獨(dú)立存放,程序在讀取它們時(shí)將會花費(fèi)比較長的時(shí)間,而且在程序里面用數(shù)組或鏈表來存放這些幀也會使代碼變得復(fù)雜。所有幀存放到一個(gè)圖片文件里面,程序執(zhí)行效率會比較高,代碼也較簡單。比如一個(gè)爆炸動畫的所有幀保存到一個(gè)圖片文件里面,如下: 11.4 生成動畫 11.4 生成動畫 如果要在屏幕上展現(xiàn)爆炸動畫,就要連續(xù)繪制圖片中的每一幀,某一特定幀
55、在圖片中的位置可以通過下列公式計(jì)算:frameX = (currentFrame%columns) * frameWidth;frameY = (currentFrame/columns) * frameHeight;frameX、frameY、frameWidth和frameHeight都是以圖片的像素為單位,currentFrame是動畫幀的序號,columns是圖片中幀的列數(shù)。11.4 生成動畫 得到幀的起始位置之后便可以使用Graphics2D的drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer)方法來繪制整個(gè)
56、圖片中的這一特定幀區(qū)域。img是包含所有幀的圖片,dx1、dy1、dx2、dy2限定了將要繪制特定幀的屏幕區(qū)域,sx1、sy1、sx2、sy2限定了圖片中特定幀的區(qū)域。11.4 生成動畫 【例11-5】AnimationTest.javaprivate void frameUpdate() /計(jì)算當(dāng)前幀在圖片中的位置frameX = (currentFrame % cols) * frameWidth;frameY = (currentFrame / cols) * frameHeight;currentFrame+;currentFrame %= totalFrames;public voi
57、d run() Thread t = Thread.currentThread();while(t=animationThread) /每顯示一幀之后,需要間隔一小段時(shí)間,/時(shí)間間隔的大小決定了動畫顯示的快慢。try Thread.sleep(20); catch (InterruptedException e) e.printStackTrace();frameUpdate();repaint();public void paint(Graphics g) Graphics2D g2d = (Graphics2D)g;if(!imageLoaded) /圖片尚未載入else /繪制每一幀前畫
58、出爆炸的背景圖片以清除前一幀 g2d.drawImage(backgroundImage, 0, 0, SCREENWIDTH-1, SCREENHEIGHT-1, this); /在屏幕中限定的區(qū)域畫出圖片中的限定區(qū)域的幀 g2d.drawImage(animationImage, SCREENWIDTH/2-frameWidth/2, SCREENHEIGHT/2-frameHeight/2, SCREENWIDTH/2-frameWidth/2+frameWidth, SCREENHEIGHT/2-frameHeight/2+frameHeight, frameX, frameY, fr
59、ameX+frameWidth, frameY+frameHeight, this);11.4 生成動畫 11.5 消除動畫閃爍運(yùn)行AnimationTest程序會發(fā)現(xiàn),爆炸動畫存在閃爍現(xiàn)象。在顯示動畫的每一幀之前,都需要先用背景圖片覆蓋前一幀,然后再顯示當(dāng)前幀,所以在程序繪制背景圖片的這一小段時(shí)間內(nèi)本應(yīng)看到動畫的前一幀,但卻看到了背景圖片,就是這一短暫的時(shí)間段導(dǎo)致了閃爍的發(fā)生。11.5 消除動畫閃爍消除閃爍的一種辦法:繪制完動畫的當(dāng)前幀,在繪制下一幀的時(shí)候,不是直接在屏幕上先繪制背景再繪制下一幀,而是先開辟一片內(nèi)存,把背景圖片和下一幀先繪制到這一片內(nèi)存區(qū)域,然后再把這片內(nèi)存中的背景圖片和下一
60、幀同時(shí)繪制到屏幕上,這樣就避免了只看到背景圖片的這一小段時(shí)間,使動畫的前后各幀連續(xù)無間隔地被游戲玩家看到,從而避免了閃爍的產(chǎn)生。 這種避免閃爍的技術(shù)就稱為雙緩沖技術(shù),開辟的這一片保存背景和動畫幀的內(nèi)存稱為緩存 。11.5 消除動畫閃爍程序中使用雙緩沖的時(shí)候,這片緩存就是java的Image對象。Image對象可以通過調(diào)用Component對象的createImage(int width, int height)方法來產(chǎn)生,其中width和height分別是創(chuàng)建的Image對象的寬度和高度。再通過Image對象的getGraphics()方法得到一個(gè)Graphics對象,這個(gè)對象的繪制圖形圖像的
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 含子女撫養(yǎng)的離婚協(xié)議書模板
- 企業(yè)運(yùn)營管理咨詢協(xié)議樣本
- 2024工程挖掘機(jī)租賃合同標(biāo)準(zhǔn)范文
- 新住宅按揭貸款合同樣本
- 2024錄制合同模板
- 2024廣告刊登協(xié)議范本
- 動物醫(yī)院聘用合同2024年
- 省級代理合作協(xié)議書的注意事項(xiàng)
- 我國自學(xué)考試網(wǎng)上輔導(dǎo)協(xié)議書樣本大全
- 2023年高考地理第一次模擬考試卷-(河北A卷)(全解全析)
- 空調(diào)安裝施工方案及空調(diào)安裝現(xiàn)場管理辦法
- 甘肅省黃金礦產(chǎn)資源概況
- 診所消防安全應(yīng)急方案
- 譯林版一年級上冊英語全冊課件
- 中小學(xué)德育工作指南考核試題及答案
- 凈現(xiàn)值NPV分析和總結(jié)
- 國網(wǎng)基建各專業(yè)考試題庫大全-質(zhì)量專業(yè)-中(多選題匯總)
- LTC流程介紹完整版
- 飼料加工系統(tǒng)粉塵防爆安全規(guī)程
- 一年級上冊美術(shù)課件-第11課-花兒寄深情-▏人教新課標(biāo)
- 植物的象征意義
評論
0/150
提交評論