Mac Development with Java

Elliotte Rusty Harold

Software Development 2006 West

Friday, March 17, 2006

elharo@metalab.unc.edu

http://www.cafeaulait.org/


Users Punish Applications with Poor Interfaces

I remember an early database, MacLion, which was a bad port of a DOS application, right down to the 24-by-80 monospaced scrolling text window. Boy, it was ugly. It eventually lost in the marketplace. Apple also spent a lot of time working with major DOS application vendors to get them to “get it” about the graphic user interface. Lotus received a lot of personal attention from Apple for their Jazz product, and later 1-2-3 for Mac.

But the folklore that has come down through the years is that Apple defended the purity of the interface by punishing the developers who built applications that broke the rules. And that’s just not true. The rules were vague; they were revised several times over the first five years; we broke the rules ourselves (starting early, with MacPaint); and to tell you the truth, we were so desperate for software that we even put that ugly, DOSish MacLion on our poster of the first 100 apps.

The truth is that the punishment for inconsistency came from the Mac community itself. Magazine reviewers and pundits were the first to appreciate the consistency and simplicity of Mac applications, especially in contrast with the growing mess in the DOS world. Influential users and purchasers followed suit. Programs with inconsistent interfaces did suffer; but they suffered at the hands of the marketplace, not of a dictatorial Apple.

I Was a Teenage Thought Policeman

Java programs that run on Mac OS X


Prerequisites for Java development on Mac OS X


Learning the Mac Interface

The Macintosh computer sports the most jumbled-up, inconsistent, confusing interface ever made, with the exception of those of all the other computers.
Tog on Interface

jEdit 4.2


What Swing Gets Right


What jEdit Gets Wrong


Determining whether you're running on Mac OS X

final static boolean thisIsAMac = System.getProperty("mrj.version") != null;


Menus Make the Difference

Users believe in the menu bar. The menu bar tells them where they are: in the safe, protective environment of the Macintosh, where consistency reigns.

The menu bar is the most constant object in the Macintosh. When it disappears, non-computer-oriented users assume they, the users, have moved, navigated, to a different planet, a world where all the rules may have changed. They are no longer within the familiar Macintosh world. And their only known way back, Quit on the menu bar, has been stripped away.

I have seen, during user testing, the very real fear etched on the face of users when the menu bar disappears. I have watched them literally panic as they realize they are trapped in a strange world.

Tog on Interface

Menu Layouts


Moving the Menubar to the Top of the Screen

    public static void main(String[] args) throws QTException {
        System.setProperty("apple.laf.useScreenMenuBar", "true");  
        System.setProperty("com.apple.eawt.CocoaComponent.CompatibilityMode", "false"); 
        // Need an empty hidden frame just for menu bar
        final PlayerFrame hidden = new PlayerFrame(true);
        // first frame is just for menu bar
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                hidden.show();
            }
        });
    } 

Application Menu


The Application Class

package com.apple.eawt;

public class Application {

    public Application();
    
    public void    addApplicationListener(ApplicationListener listener);
    public void    removeApplicationListener(ApplicationListener listener);
    public void    setEnabledPreferencesMenu(boolean enable);
    public boolean getEnabledPreferencesMenu();
    
    public static java.awt.Point getMouseLocationOnScreen();

    // New methods in Java 5 
    public static Application getApplication();

    public boolean isPreferencesMenuItemPresent();
    public void    addPreferencesMenuItem();
    public void    removePreferencesMenuItem();
    public void    removeAboutMenuItem();
    public boolean isAboutMenuItemPresent();
    public void    addAboutMenuItem();
    public boolean getEnabledAboutMenu();
    public void    setEnabledAboutMenu(boolean enable);

}

ApplicationListener


Example: Handling Quit

public void handleQuit(ApplicationEvent event) {
    Iterator iterator = WindowList.INSTANCE.iterator();
    while (iterator.hasNext()) {
        Frame next = (Frame) iterator.next();
        next.setVisible(false);
        next.dispose();
    }
    
    RecentFileList.INSTANCE.storeRecentFiles();
    System.exit(0);
}

Example: Handling About

public class MacOSHandler extends Application {

    private Dialog about;
    
    public MacOSHandler(PlayerFrame frame) {
        about = new AboutDialog(frame);
        addApplicationListener(new AboutBoxHandler());
    }

    class AboutBoxHandler extends ApplicationAdapter {
        
        public void handleAbout(ApplicationEvent event) {
            EventQueue.invokeLater(new Runnable() {
                public void run() {
                    about.setVisible(true);
                }
            });
            event.setHandled(true);
        }
        
    }
  
}

ApplicationEvent

package com.apple.eawt;

public class ApplicationEvent {

  public String   getFilename();
  public boolean  isHandled()
  public void     setHandled(boolean state) 

}

Windows vs. Mac


Removing Exit Menu Item from the File Menu

 //File -> Exit.
    if (!thisIsAMac) {
      new MenuItem(menu, SWT.SEPARATOR);
  
      //File -> Exit.
      subItem = new MenuItem(menu, SWT.NULL);
      subItem.setText(resAddressBook.getString("Exit"));
      subItem.addSelectionListener(new SelectionAdapter() {
        public void widgetSelected(SelectionEvent e) {
          shell.close();
        }
      });
    }

File/New


Edit Menu


Help Menu


Multiple Windows


Keeping the menu bar on the screen when all windows are closed

  1. Set up a special menu bar to be used when no windows are open.

  2. Add this to your first frame.

  3. Set its size to zero.

  4. Set its location to negative coordinates.

  5. Display the frame.

    PlayerFrame(boolean invisible) {
        super("");
        this.setUndecorated(true);
        this.setSize(0, 0);
        CONTROL_BAR_HEIGHT = 0;
        JMenuBar menubar = new PlayerMenuBar(null);
        this.setJMenuBar(menubar);
        this.pack();
    }

Be careful if you have any bring to Front/Send to Back/Move Forward/Move backward functionality


Window Size


Changing the Name of the Application Menu


Reserved Keys


The Mouse


General Issues


Encodings


Line ends


Special Files


Where to Store Preferences


FileManager

package com.apple.eio;

public class FileManager {

  public static void setFileTypeAndCreator(String filename, int type, int creator) throws IOException
  public static void setFileType(String filename, int type) throws IOException
  public static void setFileCreator(String filename, int creator) throws IOException
  public static int getFileType(String filename) throws IOException
  public static int getFileCreator(String filename) throws IOException
  public static String findFolder(int folderType) throws FileNotFoundException
  public static String findFolder(short domain, int folderType) throws FileNotFoundException
  public static String findFolder(short domain, int folderType, boolean createIfNeeded) throws FileNotFoundException
  public static void openURL(String url) throws IOException
  public static String getResource(String resourceName) throws FileNotFoundException   public static String getResource(String resourceName, String subDirName) throws FileNotFoundException
}

Building a Double Clickable Application


Inside the Package


Disk Images


Apple Installer


QuickTime


Calling Cocoa


Some 3rd Party Utilities You Should Know About


Steve Roy's MRJAdapter


Quaqua


A Final Thought

FileMaker MacLion
Quark XPress FrameMaker
Excel Lotus 1-2-3
Word WordPerfect
Microsoft Word 5 Microsoft Word 6
iTunes WinAmp
Adobe Illustrator CorelDraw
MacroMedia Director-->ShockWave-->Flash VRML, Java

To Learn More


Index | Cafe con Leche

Copyright 2005, 2006 Elliotte Rusty Harold
elharo@metalab.unc.edu
Last Modified January 18, 2006