Uji applet Anda dengan cara mudah: ubah menjadi aplikasi

Oke Anda sudah melewati applet Hello World dan melanjutkan ke sesuatu yang jauh lebih besar, jauh lebih menarik. Anda masih membutuhkan antarmuka berbasis browser, jadi Anda akan mengembangkan program Anda sebagai applet. Tapi debugging applet dengan memasukkan printlns di Netscape adalah beruang, dan appletviewer sepertinya tidak pernah bekerja dengan baik lagi. Atau mungkin Anda sedang menulis program yang akan berguna baik sebagai applet maupun sebagai aplikasi mandiri. Anda dapat menyisipkan mainfungsi di Appletsubkelas Anda , dan menambahkan kode untuk menangani argumen baris perintah, manipulasi jendela, dan pemuatan gambar sendiri, sekarang browser AppletContextsudah tidak ada lagi untuk Anda.

AppletContextadalah antarmuka, jadi Anda bahkan tidak bisa membuat instance AppletContextobjek untuk menyediakan fungsi yang AppletContextbiasanya disediakan browser . Tapi Anda bisa mengimplementasikan antarmuka. Dan jika Anda menerapkannya dengan cara yang sangat umum, Anda dapat menyimpannya di kotak peralatan Anda sendiri untuk digunakan kembali berulang kali. Artikel ini menunjukkan kepada Anda bagaimana melakukan hal itu. Nyatanya, Anda bahkan tidak perlu menulis implementasinya sendiri karena kode sumber disertakan di akhir artikel ini.

Kelas dan antarmuka

Untuk mencapai tujuan kami mereplikasi lingkungan berbasis browser, kami sebenarnya harus menerapkan beberapa antarmuka - khususnya, AppletContextdan AppletStub. AppletContextseharusnya mewakili lingkungan applet - biasanya browser dan dokumen HTML yang dilampirkan. The AppletStubdigunakan oleh Appletsuperclass untuk bantuan melaksanakan fungsi applet Anda dapat menghubungi seperti getAppletContext()dan getParameter(). Kami akan menerapkan satu antarmuka lain juga: URLStreamHandlerFactory. Ini akan dibahas nanti.

Karena sejauh ini kami hanya mengimplementasikan antarmuka, kami masih memiliki opsi untuk memperluas sesuatu. Browser menyediakan jendela tempat applet digambar, jadi kita membutuhkan objek Frame. Saya telah membuat kelas yang saya sebut DummyAppletContextmeluas Frame; definisinya dimulai:

public class DummyAppletContext extends Frame mengimplementasikan AppletStub, AppletContext, URLStreamHandlerFactory { 

Inisialisasi

Saya memiliki beberapa cara untuk membuat contoh DummyAppletContext; salah satu yang paling berguna adalah langsung dari mainfungsi (seperti yang ditunjukkan di bawah) di DummyAppletContextkelas itu sendiri. Dengan cara ini, saya tidak perlu mendefinisikan mainapplet apa pun hanya untuk menjalankannya sebagai aplikasi mandiri. Saya akan dapat menjalankan applet apa adanya, melalui my DummyAppletContext.

public static void main (String args []) {new DummyAppletContext (args); }

Operator baru di atas memanggil konstruktor yang mengambil daftar argumen. Saya berasumsi bahwa argumen pertama adalah nama Appletsubclass dan mencoba untuk membuat instance kelas tersebut. Saya menggunakan Classfungsi statis forName()untuk mendapatkan Classobjek, dan kemudian memanggil newInstance()fungsinya untuk membuat contoh applet. Anda bisa mendapatkan sejumlah pengecualian dari satu baris ini, dan semuanya tidak dapat dipulihkan. Jadi jika saya menemukan pengecualian apa pun, saya cukup mencetaknya dan berhenti. Jika berhasil, saya memanggil fungsi inisialisasi pribadi yang saya gunakan di semua konstruktor. Berikut adalah kode untuk konstruktornya:

public DummyAppletContext (String args []) {

super (args [0]);

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

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

Salah satu konstruktor lain (ditampilkan di bawah) mengambil objek applet yang sudah ada. Saya menggunakan konstruktor ini ketika saya ingin mengimplementasikan mainfungsi di kelas lain, seperti Appletsubclass itu sendiri. Sebenarnya ini hanya untuk kenyamanan. Dengan mainfungsi di Appletsubclass, saya bisa memulai program dengan menjalankan interpreter Java di Appletsubclass, daripada harus menjalankannya DummyAppletContextdan menentukan Appletsubclass secara terpisah ( java MyAppletversus java DummyAppletContext MyApplet). Ini juga memungkinkan saya untuk menentukan lebar dan tinggi default di applet. (Saya menyediakan satu konstruktor lain seperti ini, yang tidak memerlukan argumen lebar dan tinggi default.)

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

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

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

The initFungsi melakukan sebagian besar keajaiban setup. Argumennya mencakup objek applet, ukuran default, argumen baris perintah, dan indeks awal untuk argumen. Ingat, kami menggunakan argumen pertama di salah satu konstruktor untuk menentukan Appletsubclass yang akan dimuat, hanya berdasarkan namanya. Dalam hal ini, startidx- indeks untuk mulai mengurai argumen dan parameter applet - adalah 1, tetapi sebaliknya adalah 0. initFungsi pertama memberi tahu URLkelas bahwa objek ini sekarang akan menjadi default URLStreamHandlerFactory. (Kami mengimplementasikan antarmuka untuk ini.) Kemudian menambahkan applet yang diberikan ke vektor applet yang hanya akan berisi satu applet ini, dan ini memberitahu applet bahwa objek ini akan bertindak sebagai miliknya AppletStub. Berikut initfungsinya:

private void init (applet applet, int default_width, int default_height, String args [], int startidx) {

URL.setURLStreamHandlerFactory (ini);

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

initial_width = default_width; initial_height = default_height;

parseArgs (args, startidx);

status = new TextField (); status.setEditable (false);

add ("Center", applet); add ("Selatan", status);

applet.init (); appletResize (initial_width, initial_height);

menunjukkan(); applet.start (); }

Argumen diurai hanya dengan mengulang melalui elemen array dan menambahkan setiap pasangan argumen ke hashtable pasangan nama / nilai . Argumen -width dan -height diperlakukan secara khusus, dan menggantikan lebar dan tinggi default applet. Mereka tidak ditambahkan ke hashtable. Penguraian argumen terjadi dalam fungsi parseArgs, yang ditampilkan di sini:

public void parseArgs (String args [], int startidx) {untuk (int idx = startidx; idx <(args.length - startidx); idx + = 2) {coba {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]); }} catch (NumberFormatException nfe) {System.err.println ("Peringatan: argumen baris perintah" + args [idx] + "bukan angka yang valid."); }}}

The initFungsi terus dengan menyiapkan area status (yang digunakan oleh fungsi showStatus) menggunakan diedit objek AWT Text. Ia menambahkan komponen applet dan area status ke frame (the DummyAppletContext) sesuai dengan BorderLayoutkebijakan default , memanggil fungsi applet init, dan mengubah ukuran jendela seperti yang ditentukan. Akhirnya, jendela ditampilkan, dan applet initserta startfungsinya dipanggil. (Kami tidak pernah menelepon stop, dan starttidak pernah dipanggil lagi karena kami tidak menggunakan browser. Selain itu, saya tidak pernah menggunakan destroymetode ini untuk apa pun, jadi saya tidak menyebutnya. Tetapi jika Anda membutuhkannya, saya akan merekomendasikan untuk memanggilnya sebelum setiap System.exit()panggilan, dengan tes terlebih dahulu untuk melihat apakah init()dipanggil.)

Saya hanya perlu mengesampingkan satu fungsi Frame handleEvent(), seperti yang ditunjukkan di bawah ini, jadi saya dapat menangkap event WINDOW_DESTROY jika pengguna menekan ikon Close pada window bar.

public boolean handleEvent (Event evt) {

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

return super.handleEvent (evt); }

AppletStub

AppletStub

mendeklarasikan beberapa fungsi yang harus kita implementasikan:

  • isActive - selalu mengembalikan true

  • getDocumentBase - mengembalikan URL "file" untuk direktori saat ini

  • getCodeBase- mengembalikan hal yang sama yang getDocumentBasemengembalikan

  • getParameter- mengindeks hashtable yang kita buat parseArgsdan mengembalikan nilai yang cocok atau null jika tidak ada

  • getAppletContext- mengembalikan objek "ini" (milik kita DummyAppletContext)

  • appletResize - mencoba mengubah ukuran jendela untuk mengakomodasi 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.

private String filenameFromURL (URL url) {String filename = url.getFile (); if (filename.charAt (1) == '|') {StringBuffer buf = new StringBuffer (nama file); buf.setCharAt (1, ':'); nama file = buf.toString (); } lain jika (filename.charAt (2) == '|') {StringBuffer buf = new StringBuffer (nama file); buf.setCharAt (2, ':'); nama file = buf.toString (); } nama file kembali; }

URLStreamHandlerFactory

URLStreamHandlerFactory

hanya memiliki satu fungsi:

createURLStreamHandler()

. Saya menerapkan fungsi ini untuk menyebabkan implementasi saya

URLStreamHandler

untuk digunakan setiap kali applet mencoba membuka koneksi ke URL. Sekarang, saat aku menelepon

openStream()

pada URL di aplikasi Java saya, ini sebenarnya membuka aliran ke file lokal untuk input. Disini adalah

createURLStreamHandler()