TweetFollow Us on Twitter

A Bundle of Java

Volume Number: 15 (1999)
Issue Number: 8
Column Tag: JavaTech

A Bundle of Java

by Danny Swarzman, Stow Lake Software

Developing a stand-alone Macintosh application in Java

Preface

A typical Macintosh application allows the user to create a document, a file that contains data structured in a way that is specific to the application. The application has its own icon that appears in the Finder and an icon for each type of data the application can create or edit. A user double-clicks the application icon to launch the app.

In contrast, a Java application is typically invoked from a command line in the shell. Command line and shell are foreign expressions to most Macintosh users. They reflect Java's Unix lineage. On non-Macintosh systems, the command line is where you type in system commands, and the shell interprets and executes those commands.

Apple provides what you need to bridge the cultural gap. It's called JBindery and is included in the Macintosh Runtime for Java Software Development Kit (MRJ SDK). You can get the MRJ SDK and the latest version of MRJ from the Apple website. (The web address is provided in the References section at the end of this article.)

Using the goodies in the aforementioned SDK, you can create a full-fledged Macintosh application without writing a single line of C++ or Pascal. This article traces the steps to create a sample application.

The sample application handles multiple document windows and supports the usual File commands.

There are some features that would normally be part of a Macintosh application that are not included in this sample application. A discussion of these exercises for the reader is included near the end of this article.

The process for developing this type of application is:

  • Create the sources.
  • Create the resources.
  • Compile Java classes into a .jar (Java Archive) file.
  • Use JBindery to wrap the resources and .jar into an application.

If you use CodeWarrior Pro 4 or Pro 5, the last two steps can be combined. This article will show the process using CodeWarrior Pro 4, and a simple tic-tac-toe application. The source code for our Tic-Tac-App can be downloaded from <ftp://ftp.mactech.com/src/mactech/volume15_1999/15.08.sit>. It will also show what you need to do to bind the application when you use another compiler.

What is a Java Application?

A collection of Java classes is an application if it contains a class with a method defined as follows:

public static void main ( String args[] )

In operating systems that have a command line shell, the args parameter contains the arguments from the command line that was used to invoke the program.

There are three standard file streams available to the Java application: System.in, System.out, and System.err. Traditionally, these are assigned to a text terminal (console window) or to files.

There are Java classes for interaction with a user in an window-oriented graphic user interface. The basic classes are in the Abstract Windowing Toolkit (AWT).

There is also an extensive library of classes available for building a user interface in Java, called Swing (part of the Java Foundation Classes). Swing differs from the AWT in that its classes do not rely on platform-dependent peers for display. Instead, the Swing classes are pure Java, and can take on a variety of appearances. Since the user interface in the sample project is so simple, no Swing classes are used, only AWT.

What is a Macintosh Application?

Document Model

In a typical Macintosh application, the user interacts with a data structure through a window. The user may store and retrieve data through the File menu in the application or through the Finder.

In order for this to occur, the developer must create bundle resources and write code to create the menus and handle the events. Class libraries, such as PowerPlant, take care of most of the messy coding details.

Resource Fork and Bundle Resources

A Macintosh application, like all Macintosh files, contains a data fork and a resource fork. The data fork (for PowerPC native apps) contains the object code. Among other things, the resource fork contains bundle resources. These provide the Finder with the information it needs to associate the application and its documents with icons in the Finder.

Creator and Type

Each file is identified by two four-character designations. These are not stored as strings. They are four characters packed into a 32-bit value.

  • The creator code, or signature, in a document associates the document with an application that has the same creator code.
  • The file type identifies the structure of the data. An application may be able to handle one or several file types.

The file type 'APPL' designates the file as an application. When the user opens a document with a given creator code, the Finder will locate the application with same creator code. It will open the application and send it an event to open the document.

When the application creates document files, it must specify the signature and file type to correspond to its bundle resources.

How is a Java Application Run on the Mac?

In order for a Java program to run on the Macintosh, some Macintosh application must instantiate the Java Virtual Machine and run the Java code in the instance of the Java Virtual Machine. In order to do that, the application calls upon Macintosh Runtime for Java (MRJ). MRJ is part of the system software starting in OS 8.1. It is supplied as a code fragment, placed in the System Folder by the MRJ installer. New versions of MRJ come out frequently and are available on Apple's website.

We could call one of these applications that invokes MRJ a wrapper application. There are several forms a wrapper could take.

JRunner, included in the MRJ SDK, allows the user to specify the Java class to run and the parameters that are to be passed to main(). JRunner also accepts a variety of Apple Events so that the Java Virtual Machine can be controlled via AppleScript.

You could develop a custom wrapper application in C++. This has been discussed previously in MacTech (see "Putting Java under PowerPlant" in the October 1997 issue).

In this article, the wrapper application will generated by JBindery.

A JBound Application

Overview

JBindery automatically creates a wrapper application for a given Java program. The output of JBindery is a single file that contains the Java classes and the required resources.

Figure 1 shows the process of creating an application with JBindery.


Figure 1. Binding the application.

The basic ingredients are:

  • the compiled classes, in AppClasses.jar.
  • the resource file, TicTac.rsrc.
  • command line arguments - in this case there are no arguments.

The final result is an application, TicTacBound, containing everything needed to run. The Virtual File System contains files that can be read at runtime. The contents of the specified folder will be copied by JBindery into the Virtual File System.

Access to the Operating System

The Java program can communicate with the operating environment in several ways:

  • native methods coded in C or C++
  • calls to the Mac toolbox via JDirect
  • using the MRJToolkit for Finder and file functions

JDirect and MRJToolkit are included in the MRJ SDK. In this example only MRJToolkit will be demonstrated. Usually one would not need to write native code or call toolbox routines. There are some MRJToolkit calls, for Finder events, that work only when running in a JBound application.

To see these in use, refer to the files TicTacApp.java and TicTacDoc.java.

The ï Menu in the JBound Application

There are two commands:

  • About...
  • Quit

that appear in the ï menu of every JBound application.

Handling About... is left as an exercise for the reader. There is a place in the TicTacApp class to insert the code.

The Quit command in the ï menu duplicates the command of the same name in the sample application. This oddity causes no harm. Quitting is quitting.

Sample Application, TicTacApp


Figure 2. Playing with TicTacApp.

What It Does

The user plays tic tac toe against the program. A tic tac toe board is displayed in a window. When the user clicks on an empty square, an X appears and the program replies with an O.

There may be many games open. Each has its own window. The window title will be the file name of the game. If the game hasn't been saved, the title will be "Untitled Game", or "Untitled Game1" , etc.

When the user chooses to save the game, the current board position is written to a file. When the user opens an existing file, play can resume from the saved position.

File Menu

The only menu that is supported in the sample application is the File menu including the usual suspects:

  • New - Start an empty game in a new window. The name of the new game will be "Untitled Game", or "Untitled Game1", etc.
  • Open... - Display a file dialog to open an existing file. Display the position in the file in a new window. The user can continue the game from the current position.
  • Close - Close the window. If any plays have been made since the file was created, opened or last saved, display a dialog box asking if the user wants to save the changes before closing.
  • Save - If the game has already been saved, save the current position. If the game is still untitled, display a file dialog to allow the user to assign a name and directory to the file.
  • Save As... - Display a file dialog to allow the user to assign a name and directory to the file and save the current game.
  • Quit - Close open windows, asking the user about saving documents that have changed.

Events From the Finder

The program responds to:
  • Open - Open a new window to display the selected file.
  • Quit - Same as Quit command from the menu.

Always One Window

A Java menu is associated with a window. A JBound application will display the Java menus on the menu bar, but, still, they are associated with a specific window.

As a consequence, our application would lose control if the last window were closed. To avoid this situation, this application always displays a window. If the user closes the last open window, the application will automatically create a new untitled window.

Bundle Resources for TicTacApp

The creator code for TicTacApp is 'TicT'. The file type used is 'TEXT'. Conveniently, there are several other programs that can open documents of type 'TEXT' - CodeWarrior or SimpeText, for example.

You can create resources with a resource editor such as ResEdit or Resorcerer. Figure 3 shows the bundle resources for TicTacApp as created by ResEdit. The icons on the line labeled 'APPL' appear in the Finder for the application. Those labeled 'TEXT' will be used for documents created by the application.


Figure 3. Bundle resources for TicTacApp.

Classes in TicTacApp

The application consists of these Java classes:

  • TicTacApp The class with main(). There will be one of these objects for the entire application.
  • TicTacDoc There will be one of these for every open document. Since this class extends Frame, it displays a window.
  • TicTacSaveDialog An object of this class will ask if the user wants to save the file before closing. The dialog will call document functions CloseAndSave() and CloseNoSave() as needed.
  • TicTacCanvas An object of this class displays the board and controls the game. Each TicTacDoc has one TicTacCanvas.
  • TicTacEngine Given a board position, find the best 'O' move.

There may be many games open. Each has it own window. To create a new game in response to an Open or New command, the TicTacApp object creates a TicTacDoc object to set up the window and handle menu commands.

TicTacCanvas

Each TicTacDoc object creates a TicTacCanvas object to interact with the user.

This object displays the game board inside the TicTacDoc object's window. It responds when the user clicks a square on the game board. It creates a TicTacEngine object to find the 'O' response for the user's 'X'.

The TicTacCanvas object maintains a record of the position on the board, updating it whenever a play is made.

The TicTacDoc uses the TicTacCanvas to load and store the current game position.

The TicTacCanvas keeps track of a flag to indicate if the position on the board has been modified by the user. The flag is set when a play is made. The TicTacDoc calls the TicTacCanvas to clear the flag when a file is saved.

The functions of interest here are:

// Copy the current board position into outBytes 
public void GetBytes ( byte[] outBytes ) 
// Copy the contents of outBytes into  the current board position 
public void SetBytes ( byte[] inBytes )
// Indicate that file is up to date. 
public void ClearDirty()
// Has the user made changes since the file was last updated?
public boolean IsDirty()

TicTacApp

The main() function, which handles the command line, is here. This function creates a TicTacApp object.

The constructor, TicTacApp(), calls MRJToolkit to set up the file type and creator. It creates a new untitled document in the form of a TicTacDoc object.

The application handles commands from the Finder. It does the work for Open... and New menu commands when the TicTacDoc object receives the commands from the user.


Listing 1: TicTacApp.java



TicTacApp
/**
	TicTacApp.java
	The main class for the TicTacApp project.
*/
	import java.io.*;
	import java.util.*;
	import com.apple.mrj.*;
/**
	@author Danny Swarzman, 1999
*/
	public class TicTacApp implements MRJAboutHandler, 
		MRJOpenDocumentHandler, MRJPrintDocumentHandler, MRJQuitHandler
	{		
		//__________________________________________________________			/**
			Keep track of the number of untitled documents
			created.
		*/
		int mUntitleCount = 0;
		/**
			Names of all untitled documents start with this prefix.
		*/
		final String mUntitle = "UntitledGame";
		/**
			Count of open documents. To make sure there is always one.
		*/
		int mOpenDocsCount = 0;
		/**
			List of all open documents.
		*/
		Vector mDocumentList = new Vector();
		/**
			Flag when quit command has been received.
		*/
		boolean mQuittingTime = false;
		//__________________________________________________________			/**
			Entry point from command line.
			@param args the arguments as passed in the command line
		*/
			public static void main(String args[])
		{
			TicTacApp application = new TicTacApp();
		}
		//__________________________________________________________			/**
			Set up handlers and file types. Create the first document.
			@param inDebugOn is true when running from MetroWerks Java
			and handlers shouldn't be registered.
		*/
		public TicTacApp()
		{
			if ( MRJApplicationUtils.isMRJToolkitAvailable() )
			{
			MRJApplicationUtils.registerAboutHandler ( this );
			MRJApplicationUtils.registerOpenDocumentHandler ( this );
			MRJApplicationUtils.registerPrintDocumentHandler ( this );
			MRJApplicationUtils.registerQuitHandler ( this );
			}
			MRJOSType fileCreator = new MRJOSType ( "TicT" );
			MRJFileUtils.setDefaultFileCreator ( fileCreator );
			MRJOSType fileType = new MRJOSType ( "TEXT" );
			MRJFileUtils.setDefaultFileType ( fileType );		
				DoNew();
		}
		//__________________________________________________________			/** 
			For the first untitled game, there is no suffix.
			For all the others add the counter as a suffix.
			@return the latest title for a window of an untitled document.
		*/
		protected String Untitler ()
		{
			String result = mUntitle;
			if ( mUntitleCount > 0 )
				result = mUntitle + mUntitleCount;
			mUntitleCount++;
			return result;
		}
		//__________________________________________________________			/**
			Does nothing now. Code to display the About... box
			should be added here.
		*/
		public void handleAbout ()
		{
			// Add code to display the About... box here.
		}
		/**
			Open a document after the user has specified
			a file to open either through an open menu command
			detected by the document object or from the finder.
			@param inFile specifies filepath user has selected.
		*/
		public void handleOpenFile ( File inFile )
		{
			TicTacDoc doc = new TicTacDoc ( this, inFile );
		}
		//__________________________________________________________			/**
			Does nothing now. Code to handle the Print... 
			command should be added here.
		*/
		public void handlePrintFile ( File inFile )
		{
			// Put code to print the document here.
		}
		//__________________________________________________________			/** 
			The quit command from the Finder or in 
			response to a menu command.
		*/
		public void handleQuit()
		{
			mQuittingTime = true;
			for ( int i = mDocumentList.size()-1; i>=0; i- )
			{
				// Ask the document to close itself.
				((TicTacDoc)mDocumentList.elementAt(i)).Close();
				// When documents close themselves, they 
				// call RemoveDocument() which take the document
				// off the list. 
				// If the user canceled out of the save dialog,
				// then the document won't be closed so we shouldn't
				// quit. We detect that when the document hasn't been
				// removed from the list.
				if ( mDocumentList.size() > i )
					return;
			}	
			System.runFinalization();
			System.exit ( 0 );
		}
		//__________________________________________________________			/**
			Produce a new untitled document.
		*/
		public void DoNew ()
		{
			mOpenDocsCount++;
			TicTacDoc doc = new TicTacDoc ( this, Untitler() );
			mDocumentList.addElement ( doc );
		}
		//__________________________________________________________			/** 
			If the last window that is open, is 
			about to be closed, then open a new
			window to keep the menu bar displayed.
		*/
		public void RemoveDocument ( TicTacDoc inDocument )
		{
			mDocumentList.removeElement ( inDocument );
			if ( !mQuittingTime && -mOpenDocsCount <= 0 )
			{
					DoNew();
			}
		}		
	}		

TicTacDoc

A TicTacDoc object opens a window and creates a TicTacCanvas object to display the game and handle the game logic.

There are two constructors. New documents are constructed with a String for an untitled document. If the associated file name has already been specified, an object of class File is passed to the constructor.

The TicTacDoc object creates the menu structure. It handles all the menu commands. This includes commands that are global in scope. For those, the TicTacDoc object calls functions in the TicTacApp object.


Listing 2: TicTacDoc.java

TicTacDoc.java
/**
TicTacDoc
An object of this class handles one TicTacApp document. It displays 
the window and menus.
*/
import java.io.*;
import java.awt.*;
import java.util.Vector;
import com.apple.mrj.*;
/**
		An object of this class represents a game document.
		@author Danny Swarzman, 1999
	The document is displayed in its own window. There is a game board in the window.
	*/
public class TicTacDoc extends Frame  
{
	/** 
		The application object is used to handle 
		global requests.
	*/
	TicTacApp mApplication;
	/**
		The canvas interacts with the user to create the game.
	*/
	TicTacCanvas mCanvas;
	/**
		If the document is untitled, there is not yet a file assigned
		to its data.
	*/
	boolean mTitled = false;
	/**
		The file object specifies the filepath. It doesn't manipulate
		the actual file
	*/
	File mFile = null;
	//__________________________________________________________
	// CONSTRUCTORS							
	//__________________________________________________________			/**
		Called when the user has already selected the file.
		Build the window and set the title to the filename.
		@param inApplication The application object which will
			handle global commands.
		@param inFile Specifies the file that the user has selected.
	*/	
	public TicTacDoc ( TicTacApp inApplication, File inFile )
	{
		mApplication = inApplication;
		try 
		{
			BuildPanelsAndMenus();
			ReadDataFromFile ( inFile );
			setTitle ( inFile.getName() );
			mTitled = true;
			mFile = inFile;
		}
		catch ( FileNotFoundException e )
		{
			e.printStackTrace();
		}
		catch ( IOException e )
		{
			e.printStackTrace();
		}
	}
	//__________________________________________________________			/**
		Called to open a new untitled document.
		@param inApplication The application object which will
			handle global commands.
		@param inTitle The "Untitled..." name for the document.
	*/
	public TicTacDoc( TicTacApp inApplication, String inTitle )
	// Display one panel. 
	{
		mApplication = inApplication;
		mTitled = false;
		setTitle ( inTitle );
		BuildPanelsAndMenus();
	}
	//__________________________________________________________							
	/**
		Set up the window, menus and command key equivalents
		for the menus and show it all.
	*/
	private void BuildPanelsAndMenus()
	{
		BorderLayout lay = new BorderLayout();
		setLayout ( lay );
		mCanvas = new TicTacCanvas ();
		add ( "Center", mCanvas );
		mCanvas.resize ( 300, 200 );
		MenuBar bar = new MenuBar();
		Menu fileMenu = new Menu ( "File" );
		int itemCounter = 0;
		MenuItem newItem = new MenuItem ( "New" );
		fileMenu.add ( newItem );
		MRJMenuUtils.setMenuItemCmdKey ( fileMenu, itemCounter++, 'N' );
		MenuItem openItem = new MenuItem ( "Open..." );
		fileMenu.add ( openItem );
		MRJMenuUtils.setMenuItemCmdKey ( fileMenu, itemCounter++, 'O' );
		MenuItem closeItem = new MenuItem ( "Close" );
		fileMenu.add ( closeItem );
		MRJMenuUtils.setMenuItemCmdKey ( fileMenu, itemCounter++, 'W' );
		MenuItem saveItem = new MenuItem ( "Save" );
		fileMenu.add ( saveItem );
		MRJMenuUtils.setMenuItemCmdKey ( fileMenu, itemCounter++, 'S' );
		MenuItem saveAsItem = new MenuItem ( "Save As..." );
		fileMenu.add ( saveAsItem );
		itemCounter++;
		MenuItem separatorItem = new MenuItem ( "-" );
		fileMenu.add ( separatorItem );
		itemCounter++;
		MenuItem quitItem = new MenuItem ( "Quit" );
		fileMenu.add ( quitItem );
		MRJMenuUtils.setMenuItemCmdKey ( fileMenu, itemCounter++, 'Q' );
		bar.add ( fileMenu );
		setMenuBar ( bar );
		pack();
		show();
	}
	//__________________________________________________________			/**
		Dispatch menu command.
		@param evt The event that was detected.
		@param what The object that was detected. This is a string
		that identifies the menu command.
		@return The action got handled.
	*/
	public boolean action ( Event evt, Object what )
	{
		if ( "Quit".equals ( what ) )
		{
			Quit();
			return true;
		}
		if ( "Close".equals ( what ) )
		{
			Close();
			return true;
		}
		if ( "New".equals ( what ) )
		{
			New();
			return true;
		}
		if ( "Save As...".equals ( what ) )
		{
			SaveAs();
			return true;
		}	
		if ( "Save".equals ( what ) )
		{
			Save();
			return true;
		}	
		if ( "Open...".equals ( what ) )
		{
			Open();
			return true;
		}
		return false;
	}
	//__________________________________________________________			/**
		The only event of interest is WINDOW_DESTROY
		when user closes window.
		@param evt The event that was detected.
		@return The event got handled.
	*/
  public boolean handleEvent ( Event evt ) 
	{
		if ( evt.id == Event.WINDOW_DESTROY ) 
		{
			Close();
			return true;
		}
		return super.handleEvent ( evt );
	}
	//__________________________________________________________			//		MENU COMMAND HANDLERS
	//__________________________________________________________			/**
		New menu command.
	*/
	private void New()
	{
		mApplication.DoNew();
	}
	//__________________________________________________________			/**
		Open menu command.
	*/
	private void Open ()
	{
		FileDialog fileDialog = new FileDialog ( this, 
			"Select Game to Open", FileDialog.LOAD );
		fileDialog.show();
		String fileName = fileDialog.getFile();
		String fileDirectory = fileDialog.getDirectory();
		if ( fileName != null && fileDirectory != null )
		{
			File file = new File ( fileDirectory, fileName );
			if ( file != null )
				mApplication.handleOpenFile ( file );
		}
	}
	//__________________________________________________________			/**
		If a file has already been specified, just write the data;
		otherwise do what we do with SaveAs....
		@return The save happened. User didn't cancel.
	*/
	private boolean Save()
	{
		if ( mTitled )
		{
			WriteData ( );
			return true;
		}
		else
			return SaveAs();
	}	
	//__________________________________________________________			/**
		Prompt for a file name and save the file.
		@return The file was saved. The user didn't cancel.
	*/	
	private boolean SaveAs ()
	{
		FileDialog fileDialog = new FileDialog ( this, 
			"Save game as", FileDialog.SAVE );
		fileDialog.show();
		String fileName = fileDialog.getFile();
		if ( fileName == null )
			return false;
		String fileDirectory = fileDialog.getDirectory();
		if ( fileDirectory == null )
			return false;
		mFile = new File ( fileDirectory, fileName );
		WriteData ( );
		setTitle ( mFile.getName() );
		return true;
	}
	//__________________________________________________________			/**
		Quit menu command
	*/
	public void Quit()
	{
		mApplication.handleQuit();
	}
	//__________________________________________________________			/**
		Close menu command.
		If there are no changes, close without saving.
		If there are changes, open a dialog box to ask
		the user what to do. The dialog box will call
		CloseNoSave() or CloseAndSave() in this class
		as needed.
	*/		
	public void Close()
	{
		if ( mCanvas.IsDirty() )
		{
			TicTacSaveDialog saveDialog = new TicTacSaveDialog 
																		( this, getTitle() );
			saveDialog.show();
		}
		else
			CloseNoSave();
	}
	//__________________________________________________________			//	RESPOND TO CLOSE DIALOG CHOICES
	//__________________________________________________________			/**
		Close without saving data.
	*/
	public void CloseNoSave ()
	{
		mApplication.RemoveDocument ( this );
		dispose();		
	}			
	//__________________________________________________________			/**
		Save data, then save.
	*/
	public void CloseAndSave()
	{
		if ( Save() )
			CloseNoSave();
	}
	//__________________________________________________________			// FILE IO
	//__________________________________________________________							
	/**
		Open file and read the data.
		@param inFile Filespec for the file to read.
	*/
	private void ReadDataFromFile ( File inFile ) 
		throws FileNotFoundException, IOException
	{
		FileInputStream inputStream =
			new FileInputStream ( inFile );
		byte[] data = new byte[9];
		inputStream.read ( data );
		inputStream.close();
		mCanvas.SetBytes ( data );
	}
	//__________________________________________________________			/**
		Open file and write the data.
		@param inFile Filespec for the file to write.
	*/
	private void WriteData ( )
	{
			try
			{
				FileOutputStream outputStream =
					new FileOutputStream ( mFile );
				byte[] data = new byte[9];
				mCanvas.GetBytes ( data );
				outputStream.write ( data, 0, 9 );
				outputStream.close ();
				mCanvas.ClearDirty();
			}
			catch ( IOException e )
			{
				e.printStackTrace();
			}
	}
}

Developing the Project in CodeWarrior

Setting up the Project in CodeWarrior

The CodeWarrior IDE will automatically invoke JBindery if you set it up correctly as described below. The description below uses CodeWarrior Pro 4, and assumes the source and resource files were already created.

  • Create a folder, TicTacProjectFolder. Fill it with the source and resource files arranged as shown in Figure 4.


Figure 4. The project in CodeWarrior.

  • Open CodeWarrior and create a new project. Choose to make it a Java application. The default application will contain Classes.zip, the Java Class Library and TrivialApplication.java.
  • Remove the source file, TrivialApplication.java.
  • Add MRJToolkitStubs.zip from the MRJToolkit folder of the MRJ SDK.
  • Add the source files, TicTacEngine.java, TicTacApp.java, TicTacCanvas.java, TicTacDoc.java, and SaveDialog.java.
  • Add the resource file, TicTac.rsrc.
  • Arrange the project window to get something like Figure 5.


Figure 5. The files in the project.

  • Open up the settings dialog through the command in the Edit menu.
  • In the Target Settings panel set the Post-linker: to Java Mac OS Post Linker.
  • In File Mappings add the extension .rsrc. Set the compiler to JAR Importer. Set the file type to rsrc.
  • In Java Target set the Main Class to TicTacApp and the Virtual Machine to Apple MRJ.
  • In JavaCommandLine set the Main Class Name to TicTacApp.
  • In Java MacOS Settings set the MacOS Java Output to JBindery. Set the Creator to TicT and the Output filename to TicTacBound. Check Merge zip file into App. See Figure 6.


Figure 6. Setting up CodeWarrior to use JBindery.

  • Close the settings dialog, clicking Save.
  • In the project menu select the resource file. In the Windows menu choose Project Inspector. In the Project Inspector window click Merge Into Output and Save it.

Debugging in CodeWarrior

Once the project is set up, the Make command in the Project menu will produce AppClasses.jar and TacTacBound. To debug the project:
  • Open AppClasses.jar in the CodeWarrior IDE and set your breakpoints.
  • Open the application, TacTacBound in the Finder. As your program runs, it will stop at the breakpoints.

To make changes in the code:

  • Quit the application, TacTacBound.
  • Change the code in the source file in CodeWarrior.
  • Open the application, TacTacBound in the Finder. As long as you didn't close the window for AppClasses.jar, the program will stop at breakpoints.

You may be tempted to use the Enable Debugger command from the Project menu. That may work. It invokes an application called Metrowerks Java. It is not recommended by Apple or by Metrowerks. Metrowerks Java is buggy and will be discontinued after CW Pro 4.

Developing The Project with JBindery

If you are not using CodeWarrior Pro 4 or CodeWarrior Pro 5, you will need to compile the Java code, and use JBindery directly. Here we assume you start with the Java Archive, AppClasses.jar and the resource file . Before starting, put AppClasses.jar into a folder as the only file in that folder. Name the folder TicTacPackage.

JBindery displays a window that resembles a settings dialog with the various categories of information on its panel. See Figure 5.

Command

Specify the information that otherwise would be included in the command line. This is passed to main() in the application.

In this example, main() in class TicTacApp will be called with an array of length zero as the arg[] parameter. See Figure 7.


Figure 7. Specifying the command line info.

The Virtual File System

A folder full of files can be packaged with the application generated by JBindery. They will be appended to the application code in the data fork.

The AddFolder... button opens a dialog to select the folder. In this case, the TicTacPackage folder contains one file, AppClassesjar. Select TicTacPackage in the scroll box and click Make VFS. See Figure 8.


Figure 8. Setting up the Virtual File System.

Specifying Creator Code and Bundle Resources

JBindery will generate a file of type 'APPL' . It's creator code will be 'TicT' as specified in the dialog box shown in Figure 9. Resource file, TicTac.rsrc contains the bundle resources to provide icons for the application and the documents it creates.


Figure 9. Telling JBindery about the bundle.

Exercises for the Reader

The sample code handles neither the Print... command nor the About... command. If your user interface is of any more complexity, you may consider using the Swing classes supplied by Sun.

Conclusions

JBindery provides the developer with the means to develop a full-fledged Macintosh application in Java. It can be useful to developers who want to port Java applications from other platforms as well as those developing primarily on the Mac.

There are only two oddities that the user might notice. The extra Quit in the ï menu causes no problems for the user. The fact that there always needs to be at least one window open may seem a little bit strange. Otherwise, the user would have little reason to know or care that the application is a Java app.

Developing with CodeWarrior makes using JBindery easier. This article discussed the steps involved in using Pro 4. In Pro 5, which is nearing release as this article goes to press, it is about as easy to develop a Macintosh application in Java as it is in C++. Maybe in a future article...

References

Credits

Thanks to Victoria Leonard for the artwork and editing. Thanks also to Bob Ackerman for reviewing the work in progress.


Danny Swarzman develops software for fun and games. Fun for the users that is – he does it to earn money as a consultant. He also works to improve his game-playing skills at the San Francisco Go Club. He has been sighted at http://www.stowlake.com. Send comments, questions and job offers to dannys@stowlake.com.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Vivaldi 1.7.735.46 - An advanced browser...
Vivaldi is a browser for our friends. In 1994, two programmers started working on a web browser. Our idea was to make a really fast browser, capable of running on limited hardware, keeping in mind... Read more
HandBrake 1.0.3 - Versatile video encode...
HandBrake is a tool for converting video from nearly any format to a selection of modern, widely supported codecs. Features Supported Sources VIDEO_TS folder, DVD image or real DVD (unencrypted... Read more
Slack 2.5.1 - Collaborative communicatio...
Slack is a collaborative communication app that simplifies real-time messaging, archiving, and search for modern working teams. Version 2.5.1: New The way we load teams you don't view often has been... Read more
BBEdit 11.6.4 - Powerful text and HTML e...
BBEdit is the leading professional HTML and text editor for the Mac. Specifically crafted in response to the needs of Web authors and software developers, this award-winning product provides a... Read more
BBEdit 11.6.4 - Powerful text and HTML e...
BBEdit is the leading professional HTML and text editor for the Mac. Specifically crafted in response to the needs of Web authors and software developers, this award-winning product provides a... Read more
beaTunes 4.6.12 - Organize your music co...
beaTunes is a full-featured music player and organizational tool for music collections. How well organized is your music Library? Are your artists always spelled the same way? Any R.E.M. vs REM?... Read more
Tinderbox 7.0.1 - Store and organize you...
Tinderbox is a personal content management assistant. It stores your notes, ideas, and plans. It can help you organize and understand them. And Tinderbox helps you share ideas through Web journals... Read more
FotoMagico 5.4 - Powerful slideshow crea...
FotoMagico lets you create professional slideshows from your photos and music with just a few, simple mouse clicks. It sports a very clean and intuitive yet powerful user interface. High image... Read more
Direct Mail 4.3.9 - Create and send grea...
Direct Mail is an easy-to-use, fully-featured email marketing app purpose-built for OS X. It lets you create and send great looking email campaigns. Start your newsletter by selecting from a gallery... Read more
Tinderbox 7.0.1 - Store and organize you...
Tinderbox is a personal content management assistant. It stores your notes, ideas, and plans. It can help you organize and understand them. And Tinderbox helps you share ideas through Web journals... Read more

The best sales on the App Store this wee...
The App Store has quite an exciting lineup of discount games this week that range across a variety of genres. It's a great opportunity to catch up on some of the premium games you may have been holding off on -- and some you can even grab for free... | Read more »
The best new games we played this week
Ah, here we are again at the close of another busy week. Don't rest too easy, though. We had a lot of great new releases in mobile games this week, and now you're going to have to spend all weekend playing them. That shouldn't be too much of a... | Read more »
Rollercoaster Tycoon Touch Guide: How to...
| Read more »
Rabbids Crazy Rush Guide: How to unlock...
The Rabbids are back in a new endless running adventure, Rabbids Crazy Rush. It's more ridiculous cartoon craziness as you help the little furballs gather enough fuel (soda) to get to the moon. Sure, it's a silly idea, but everyone has dreams --... | Read more »
Tavern Guardians (Games)
Tavern Guardians 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: Tavern Guardians is a Hack-and-Slash action game played in the style of a match-three. You can experience high pace action... | Read more »
Slay your way to glory in idle RPG Endle...
It’s a golden age for idle games on the mobile market, and those addictive little clickers have a new best friend. South Korean developer Ekkorr released Endless Frontier last year, and players have been idling away the hours in the company of its... | Read more »
Tiny Striker: World Football Guide - How...
| Read more »
Good news everyone! Futurama: Worlds of...
Futurama is finding a new home on mobile in TinyCo and Fox Interactive's new game, Futurama: Worlds of Tomorrow. They're really doing it up, bringing on board Futurama creator Matt Groening along with the original cast and writers. TinyCo wants... | Read more »
MUL.MASH.TAB.BA.GAL.GAL (Games)
MUL.MASH.TAB.BA.GAL.GAL 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: ENDLESS UPGRADES. CONSTANT DANGER. ANCIENT WISDOM. BOUNCY BALLS. Launch Sale, 40% OFF for a very limited time!!! MUL.... | Read more »
Dungeon Rushers (Games)
Dungeon Rushers 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: Dungeon Rushers is a 2D tactical RPG combining dungeon crawler’s gameplay and turn based fights. Manage your team, loot dusty... | Read more »

Price Scanner via MacPrices.net

12-inch 1.2GHz Retina MacBooks on sale for $2...
Newegg has the 12″ 1.2GHz Space Gray Retina MacBook (sku MLH82LL/A) on sale for $1349.99 including free shipping. Their price is $250 off MSRP, and it’s the lowest price available for this model.... Read more
13-inch MacBook Airs on sale for $100 off MSR...
B&H Photo has 13″ MacBook Airs on sale for $100 off MSRP. Shipping is free, and B&H charges NY sales tax only: - 13″ 1.6GHz/128GB MacBook Air (MMGF2LL/A): $899 $100 off MSRP - 13″ 1.6GHz/... Read more
9-inch 32GB Silver iPad Pro on sale for $549,...
B&H Photo has the 9.7″ 32GB Silver Apple iPad Pro on sale for $549 for a limited time. Shipping is free, and B&H charges NY sales tax only. Their price is $50 off standard MSRP for this model... Read more
13-inch 2.0GHz Apple MacBook Pros on sale for...
B&H has the non-Touch Bar 13″ 2.0GHz MacBook Pros in stock today and on sale for $100 off MSRP. Shipping is free, and B&H charges NY sales tax only: - 13″ 2.0GHz MacBook Pro Space Gray (... Read more
15-inch Touch Bar MacBook Pros on sale for up...
B&H Photo has the new 2016 15″ Apple Touch Bar MacBook Pros in stock today and on sale for up to $150 off MSRP. Shipping is free, and B&H charges NY sales tax only: - 15″ 2.7GHz Touch Bar... Read more
12-inch Retina MacBooks on sale for $1150, $1...
B&H has 12″ 1.1GHz Retina MacBooks on sale for $150 off MSRP. Shipping is free, and B&H charges NY sales tax only: - 12″ 1.1GHz Space Gray Retina MacBook: $1149 $150 off MSRP - 12″ 1.1GHz... Read more
Apple restocks refurbished 11-inch MacBook Ai...
Apple has Certified Refurbished 11″ MacBook Airs (the latest models recently discontinued by Apple), available for up to $170 off original MSRP. An Apple one-year warranty is included with each... Read more
Apple Park Opens to Employees in April With T...
Apple has announced that Apple Park, the company’s new 175-acre campus, will be ready for employees to begin occupying in April. The process of moving more than 12,000 people will take over six... Read more
Manhattan Neighbors for Safer Telecommunicati...
A new education and advocacy group focused on cell phone and wireless risks, Manhattan Neighbors for Safer Telecommunications, launched today at http://www.ManhattanNeighbors.org. Manhattan... Read more
Portable Dual DisplayPort Monitor Dock Enable...
IOGEAR has announced the launch of its USB-C Dual DisplayPort Monitor Portable Dock (GUC3CMST). The dock enables users to easily connect two DisplayPort monitors to a USB-C or Thunderbolt 3 laptop to... Read more

Jobs Board

*Apple* Wireless Lead - T-ROC - The Retail O...
…of knowledge in wireless sales and activations to the Beautiful and NEW APPLE Experiencestore within MACYS. THIS role, APPLE Wireless Lead, isbrandnewas MACYS Read more
Manager *Apple* Systems Administration - Pu...
Req ID 3315BR Position Title Manager, Apple Systems Administration Job Description The Manager of Apple Systems Administration oversees the administration and Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Retail - Multiple Positions- Chicago...
SalesSpecialist - Retail Customer Service and SalesTransform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
Manager *Apple* Systems Administration - Pu...
Req ID 3315BR Position Title Manager, Apple Systems Administration Job Description The Manager of Apple Systems Administration oversees the administration and Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.