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 println
s 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 main
fungsi di Applet
subkelas anda , dan menambahkan kod untuk menangani argumen baris perintah, manipulasi tetingkap, dan memuatkan gambar sendiri, sekarang kerana penyemak imbas AppletContext
tidak lagi ada untuk anda.
AppletContext
adalah antara muka, jadi anda bahkan tidak dapat membuat AppletContext
objek untuk menyediakan fungsi yang AppletContext
biasanya 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, AppletContext
dan AppletStub
. AppletContext
sepatutnya mewakili persekitaran applet - biasanya penyemak imbas dan melampirkan dokumen HTML. Ini AppletStub
digunakan oleh Applet
superclass 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 DummyAppletContext
yang 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 main
fungsi (seperti gambar di bawah) di DummyAppletContext
kelas itu sendiri. Dengan cara ini, saya tidak perlu menentukan main
dalam 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 Applet
subkelas dan cuba memberi contoh kelas. Saya menggunakan Class
fungsi statik forName()
untuk mendapatkan Class
objek, 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 main
fungsi di kelas lain, seperti Applet
subkelas itu sendiri. Sebenarnya, ini hanyalah kemudahan. Dengan main
fungsi di Applet
subkelas, saya dapat memulai program dengan menjalankan juru bahasa Java pada Applet
subkelas, daripada harus menjalankannya DummyAppletContext
dan menentukan Applet
subkelas secara terpisah ( java MyApplet
lawan 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 init
fungsi 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 Applet
subkelas 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. init
Fungsi pertama memberitahu URL
kelas 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 init
fungsinya:
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 init
fungsi 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 BorderLayout
kebijakan default , memanggil init
fungsi applet , dan mengubah ukuran jendela seperti yang ditentukan. Akhirnya, tetingkap dipaparkan, dan applet init
dan start
fungsi dipanggil. (Kami tidak perlu menelefon stop
, dan start
tidak pernah dipanggil lagi kerana kami tidak berada dalam penyemak imbas. Juga, saya tidak pernah menggunakan destroy
kaedah 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 benargetDocumentBase
- mengembalikan URL "fail" untuk direktori semasagetCodeBase
- mengembalikan perkara yang sama yanggetDocumentBase
kembaligetParameter
- mengindeks hashtable yang kami binaparseArgs
dan mengembalikan nilai yang sepadan atau nol jika tidak adagetAppletContext
- mengembalikan objek "ini" (kamiDummyAppletContext
)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 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.
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()