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 println
s 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 main
fungsi di Applet
subkelas Anda , dan menambahkan kode untuk menangani argumen baris perintah, manipulasi jendela, dan pemuatan gambar sendiri, sekarang browser AppletContext
sudah tidak ada lagi untuk Anda.
AppletContext
adalah antarmuka, jadi Anda bahkan tidak bisa membuat instance AppletContext
objek untuk menyediakan fungsi yang AppletContext
biasanya 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, AppletContext
dan AppletStub
. AppletContext
seharusnya mewakili lingkungan applet - biasanya browser dan dokumen HTML yang dilampirkan. The AppletStub
digunakan oleh Applet
superclass 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 DummyAppletContext
meluas 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 main
fungsi (seperti yang ditunjukkan di bawah) di DummyAppletContext
kelas itu sendiri. Dengan cara ini, saya tidak perlu mendefinisikan main
applet 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 Applet
subclass dan mencoba untuk membuat instance kelas tersebut. Saya menggunakan Class
fungsi statis forName()
untuk mendapatkan Class
objek, 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 main
fungsi di kelas lain, seperti Applet
subclass itu sendiri. Sebenarnya ini hanya untuk kenyamanan. Dengan main
fungsi di Applet
subclass, saya bisa memulai program dengan menjalankan interpreter Java di Applet
subclass, daripada harus menjalankannya DummyAppletContext
dan menentukan Applet
subclass secara terpisah ( java MyApplet
versus 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 init
Fungsi 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 Applet
subclass yang akan dimuat, hanya berdasarkan namanya. Dalam hal ini, startidx
- indeks untuk mulai mengurai argumen dan parameter applet - adalah 1, tetapi sebaliknya adalah 0. init
Fungsi pertama memberi tahu URL
kelas 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 init
fungsinya:
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 init
Fungsi 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 BorderLayout
kebijakan default , memanggil fungsi applet init
, dan mengubah ukuran jendela seperti yang ditentukan. Akhirnya, jendela ditampilkan, dan applet init
serta start
fungsinya dipanggil. (Kami tidak pernah menelepon stop
, dan start
tidak pernah dipanggil lagi karena kami tidak menggunakan browser. Selain itu, saya tidak pernah menggunakan destroy
metode 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 truegetDocumentBase
- mengembalikan URL "file" untuk direktori saat inigetCodeBase
- mengembalikan hal yang sama yanggetDocumentBase
mengembalikangetParameter
- mengindeks hashtable yang kita buatparseArgs
dan mengembalikan nilai yang cocok atau null jika tidak adagetAppletContext
- mengembalikan objek "ini" (milik kitaDummyAppletContext
)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 theDummyAppletContext
, 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 thisAppletContext
. There is only one, so this returns an Enumeration of one element. The Enumeration is created from the Vector we filled in theinit
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 theText
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()