Uji applet anda dengan cara yang mudah: ubah menjadi aplikasi

OK Anda melewati applet Hello World dan meneruskan sesuatu yang jauh lebih besar, lebih menarik. Anda masih memerlukan antara muka berasaskan penyemak imbas, jadi anda akan mengembangkan program anda sebagai applet. Tetapi menyahpepijat applet dengan memasukkan printlns di Netscape adalah beruang, dan peninjau applet nampaknya tidak berfungsi dengan baik lagi. Atau mungkin anda sedang menulis program yang akan berguna sebagai applet dan sebagai aplikasi mandiri. Anda boleh memasukkan mainfungsi di Appletsubkelas anda , dan menambahkan kod untuk menangani argumen baris perintah, manipulasi tetingkap, dan memuatkan gambar sendiri, sekarang kerana penyemak imbas AppletContexttidak lagi ada untuk anda.

AppletContextadalah antara muka, jadi anda bahkan tidak dapat membuat AppletContextobjek untuk menyediakan fungsi yang AppletContextbiasanya disediakan oleh penyemak imbas . Tetapi anda boleh melaksanakan antara muka. Dan jika anda menerapkannya dengan cara yang sangat generik, anda boleh meletakkannya di peti alat anda sendiri untuk digunakan berulang kali. Artikel ini menunjukkan kepada anda cara melakukannya. Sebenarnya, anda tidak perlu menulis sendiri pelaksanaannya kerana kod sumbernya disertakan pada akhir artikel ini.

Kelas dan antara muka

Untuk mencapai tujuan kita mereplikasi persekitaran berasaskan penyemak imbas, kita sebenarnya harus melaksanakan beberapa antara muka - khususnya, AppletContextdan AppletStub. AppletContextsepatutnya mewakili persekitaran applet - biasanya penyemak imbas dan melampirkan dokumen HTML. Ini AppletStubdigunakan oleh Appletsuperclass untuk membantu melaksanakan fungsi applet yang mungkin anda panggil seperti getAppletContext()dan getParameter(). Kita akan melaksanakan satu antara muka yang lain juga: URLStreamHandlerFactory. Perkara ini akan dibincangkan kemudian.

Oleh kerana kami hanya melaksanakan antara muka setakat ini, kami masih mempunyai pilihan untuk memperluas sesuatu. Penyemak imbas menyediakan tetingkap di mana applet digambar, jadi kami memerlukan objek Frame. Saya telah membuat kelas yang saya panggil DummyAppletContextyang meluas Frame; definisinya bermula:

kelas awam DummyAppletContext memanjangkan Frame menerapkan AppletStub, AppletContext, URLStreamHandlerFactory { 

Permulaan

Saya mempunyai beberapa cara untuk mewujudkan DummyAppletContext; salah satu yang paling berguna adalah langsung dari mainfungsi (seperti gambar di bawah) di DummyAppletContextkelas itu sendiri. Dengan cara ini, saya tidak perlu menentukan maindalam applet apa pun untuk menjalankannya sebagai aplikasi yang berdiri sendiri. Saya akan dapat menjalankan applet sebagaimana adanya, melalui saya DummyAppletContext.

utama kekosongan statik awam (String args []) {new DummyAppletContext (args); }

Pengendali baru di atas memanggil pembina yang mengambil senarai hujah. Saya menganggap bahawa argumen pertama adalah nama Appletsubkelas dan cuba memberi contoh kelas. Saya menggunakan Classfungsi statik forName()untuk mendapatkan Classobjek, dan kemudian memanggil newInstance()fungsinya untuk memberi contoh applet. Anda boleh mendapatkan pelbagai pengecualian dari satu baris ini, dan semuanya tidak dapat dipulihkan. Oleh itu, jika saya mendapat pengecualian, saya hanya mencetaknya dan berhenti. Sekiranya ia berfungsi, saya memanggil fungsi inisialisasi persendirian yang saya gunakan di semua pembina. Berikut adalah kod untuk pembina:

umum DummyAppletContext (String args []) {

super (berhujah [0]);

cuba {Applet applet = (Applet) Class.forName (args [0]) .newInstance ();

init (applet, 640, 480, args, 1); } tangkapan (Pengecualian e) {e.printStackTrace (); System.exit (1); }}

Salah satu pembina lain (ditunjukkan di bawah) mengambil objek applet yang ada. Saya menggunakan konstruktor ini semasa saya mahu melaksanakan mainfungsi di kelas lain, seperti Appletsubkelas itu sendiri. Sebenarnya, ini hanyalah kemudahan. Dengan mainfungsi di Appletsubkelas, saya dapat memulai program dengan menjalankan juru bahasa Java pada Appletsubkelas, daripada harus menjalankannya DummyAppletContextdan menentukan Appletsubkelas secara terpisah ( java MyAppletlawan java DummyAppletContext MyApplet). Ini juga membolehkan saya menentukan lebar dan tinggi lalai dalam applet. (Saya menyediakan satu pembina lain seperti ini, yang tidak memerlukan argumen lebar dan tinggi lalai.)

public DummyAppletContext (Applet applet, int default_width, int default_height, String args []) {

super (applet.getClass (). getName ());

init (applet, default_width, default_height, args, 0); }

Yang initfungsi tidak kebanyakan sihir persediaan. Argumennya termasuk objek applet, ukuran lalai, argumen baris perintah, dan indeks permulaan untuk argumen. Ingat, kami menggunakan argumen pertama di salah satu pembangun untuk menentukan Appletsubkelas yang akan dimuat, dengan namanya sahaja. Dalam kes itu, startidx- indeks dari mana untuk mula menguraikan argumen dan parameter applet - adalah 1, tetapi sebaliknya adalah 0. initFungsi pertama memberitahu URLkelas bahawa objek ini sekarang akan menjadi lalai URLStreamHandlerFactory. (Kami menerapkan antara muka untuk ini.) Kemudian menambahkan applet yang diberikan ke Vector applet yang hanya akan berisi applet yang satu ini, dan ia memberitahu applet bahawa objek ini akan bertindak seperti itu AppletStub. Inilah initfungsinya:

init kekosongan peribadi (applet applet, int default_width, int default_height, String args [], int startidx) {

URL.setURLStreamHandlerFactory (ini);

applets.addElement (applet); applet.setStub (ini);

permulaan_ lebar = lebar_ lalai; initial_height = default_height;

parseArgs (args, startidx);

status = TextField baru (); status.setEditable (palsu);

tambah ("Pusat", applet); tambah ("Selatan", status);

applet.init (); appletResize (lebar_ awal, ketinggian_ awal);

tunjuk (); applet.start (); }

Argumen diuraikan dengan hanya mengulangi elemen larik dan menambahkan setiap pasangan argumen ke pasangan nama / nilai yang dapat dicantumkan. Argumen- lebar dan tinggi diperlakukan khas, dan mengatasi lebar dan tinggi lalai applet. Mereka tidak ditambahkan ke hashtable. Penghuraian argumen berlaku dalam fungsi parseArgs, ditunjukkan di sini:

public void parseArgs (String args [], int startidx) {untuk (int idx = startidx; idx <(args.length - startidx); idx + = 2) {cuba {if (args [idx] .equals ("-width" )) {initial_width = Integer.parseInt (args [idx + 1]); } lain jika (args [idx] .equals ("-height")) {initial_height = Integer.parseInt (args [idx + 1]); } lain {params.put (args [idx], args [idx + 1]); }} tangkapan (NumberFormatException nfe) {System.err.println ("Peringatan: argumen baris perintah" + args [idx] + "bukan nombor yang sah."); }}}

Yang initfungsi terus dengan menubuhkan kawasan status (digunakan oleh fungsi showStatus) menggunakan objek AWT Text boleh diedit. Ini menambahkan komponen applet dan area status ke frame (the DummyAppletContext) sesuai dengan BorderLayoutkebijakan default , memanggil initfungsi applet , dan mengubah ukuran jendela seperti yang ditentukan. Akhirnya, tetingkap dipaparkan, dan applet initdan startfungsi dipanggil. (Kami tidak perlu menelefon stop, dan starttidak pernah dipanggil lagi kerana kami tidak berada dalam penyemak imbas. Juga, saya tidak pernah menggunakan destroykaedah untuk apa-apa, jadi saya tidak memanggilnya. Tetapi jika anda memerlukannya, saya akan mengesyorkan memanggilnya sebelum setiap System.exit()panggilan, dengan ujian terlebih dahulu untuk mengetahui apakah init()panggilan itu dipanggil.)

Saya hanya perlu mengganti satu fungsi Frame handleEvent(), seperti yang ditunjukkan di bawah ini, jadi saya dapat menangkap peristiwa WINDOW_DESTROY jika pengguna menekan ikon Tutup pada bar tetingkap.

public boolean handleEvent (Event evt) {

jika (evt.id == Event.WINDOW_DESTROY) {System.exit (0); }

kembali super.handleEvent (evt); }

AppletStub

AppletStub

menyatakan beberapa fungsi yang harus kita laksanakan:

  • isActive - selalu kembali benar

  • getDocumentBase - mengembalikan URL "fail" untuk direktori semasa

  • getCodeBase- mengembalikan perkara yang sama yang getDocumentBasekembali

  • getParameter- mengindeks hashtable yang kami bina parseArgsdan mengembalikan nilai yang sepadan atau nol jika tidak ada

  • getAppletContext- mengembalikan objek "ini" (kami DummyAppletContext)

  • appletResize - percubaan untuk mengubah ukuran tetingkap untuk menampung permintaan untuk mengubah ukuran applet

Most of these functions are pretty straightforward. However, I did have to do some special things to make getDocumentBase to work the way I wanted it to. I started by creating a reference to a dummy file. Using an object of the File class, I called getAbsolutePath() to get the full path name of the file. For DOS (Windows), I had a file name with a bunch of backslashes in it. My objective was to create a URL, so I had to replace these slashes with forward slashes. Also, the typical browser expects the colon (:) in a DOS filename to be replaced with a vertical bar (|) in the URL. The code below performs a transformation of the dummy file to what appears to be a Netscape-compliant URL.

 public URL getDocumentBase() { URL url = null; try { File dummy = new File( "dummy.html" ); String path = dummy.getAbsolutePath(); if ( ! File.separator.equals( "/" ) ) { StringBuffer buffer = new StringBuffer(); if ( path.charAt(0) != File.separator.charAt(0) ) { buffer.append( "/" ); } StringTokenizer st = new StringTokenizer( path, File.separator ); while ( st.hasMoreTokens() ) { buffer.append( st.nextToken() + "/" ); } if ( File.separator.equals( "\\" ) && ( buffer.charAt(2) == ':' ) ) ' );  else { } path = buffer.toString(); path = path.substring( 0, path.length()-1 ); } url = new URL( "file", "", -1, path ); } catch ( MalformedURLException mue ) { mue.printStackTrace(); } return url; } 

The only other AppletStub function implementation of note is appletResize(). In this function, I not only found that I needed to take into account the size of the status text box, but I also had to accomodate the window decorations (for example, the title bar). Java provides the function needed to get that information in Frame's insets() function. Here is the appletResize function:

public void appletResize( int width, int height ) {

Insets insets = insets();

resize( ( width + insets.left + insets.right ), ( height + status.preferredSize().height + insets.top + insets.bottom ) ); }

AppletContext

The functions required to implement

AppletContext

include:

  • getAudioClip -- returns null, because there doesn't seem to be a toolkit for audio clips in my JDK. (You could handle this differently, returning your own implementation of AudioClip.)

  • getImage -- gets an image from the given URL. For the purposes of the DummyAppletContext, all URLs are assumed to be references to a local file. Therefore getImage converts the URL to a file name, and uses the AWT Toolkit object to load the image.

  • getApplet -- is supposed to return an applet by name. I never name my applet, and there are no other applets, so this always returns null.

  • getApplets -- returns an Enumeration of the applets in this AppletContext. There is only one, so this returns an Enumeration of one element. The Enumeration is created from the Vector we filled in the init function.

  • showDocument -- There are two variations of this function, neither one of which actually shows a document. In a browser, showDocument requests that a document at the given URL be loaded. I actually do show this request in the status area, but I don't attempt to retrieve or show the document.

  • showStatus -- writes the given text to the Text object used as the status area.

The getImage() function uses a private function filenameFromURL() to convert the URL back to a legal file name for the current operating system. Again, I have to make special provisions for DOS, taking into account variations I have seen from time to time. In particular, I have to convert the URL's vertical bar back to a colon.

nama fail String peribadiFromURL (URL url) {String filename = url.getFile (); if (nama fail.charAt (1) == '|') {StringBuffer buf = StringBuffer baru (nama fail); buf.setCharAt (1, ':'); nama fail = buf.toString (); } lain jika (nama fail.charAt (2) == '|') {StringBuffer buf = StringBuffer baru (nama fail); buf.setCharAt (2, ':'); nama fail = buf.toString (); } kembalikan nama fail; }

URLStreamHandlerFactory

URLStreamHandlerFactory

hanya mempunyai satu fungsi:

createURLStreamHandler()

. Saya melaksanakan fungsi ini untuk menyebabkan pelaksanaan saya

URLStreamHandler

untuk digunakan setiap kali applet cuba membuka sambungan ke URL. Sekarang, semasa saya menelefon

openStream()

pada URL dalam aplikasi Java saya, ia sebenarnya membuka aliran ke fail tempatan untuk input. Di sini

createURLStreamHandler()