Write Twice, Run Anywhere
Pages: 1, 2, 3
Creating the Menu Items
The Open menu item is exactly the same in both the Windows and the Mac versions.
Here's the code for OpenMenuItem.
package commonGUI;
import javax.swing.JMenuItem;
import javax.swing.KeyStroke;
import java.awt.event.KeyEvent;
import java.awt.Toolkit;
public class OpenMenuItem extends JMenuItem {
public OpenMenuItem(){
super("Open...");
setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
}
}
The highlighted line above is where all the magic happens. The first parameter being passed into the getKeyStroke() method is the key event that corresponds to typing the letter "O". On a Mac you type Command - O to select the Open menu item and on Windows you type Control - O. The second parameter retrieves the mask for the menu shortcut key on the platform your application is running. Rather than hardcode in the Control key or the Command key, you retrieve the information at runtime. First the Toolkit's static method getDefaultToolkit() gives you a handle to the current AWT toolkit. Then that toolkit is queried for the mask for the menu shortcut key. On a Windows box it returns the mask for the Control key and on a Mac it returns the mask for the Command key. This allows the OpenMenuItem to look as it should in both environments.
The Page Setup menu item is common to both the Mac and Windows File menus but it has an accelerator assigned on the Mac but not on Windows. We can build a common parent class and place it in the commonGUI package and then extend it on the Mac and add the accelerator. When you add behavior to Page Setup you can then do it in the common parent class and reduce the amount of duplicated code. Here's the root class, PageSetupMenuItem.
package commonGUI;
import javax.swing.JMenuItem;
public class PageSetupMenuItem extends JMenuItem{
public PageSetupMenuItem(){
super("Page Setup...");
}
}
Now extend PageSetupMenuItem and add the keyboard accelerator in the constructor. Remember that the no argument constructor in the parent class will be the first thing called by the constructor in MacPageSetupMenuItem.
package MacGUI;
import commonGUI.PageSetupMenuItem;
import javax.swing.KeyStroke;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
public class MacPageSetupMenuItem extends PageSetupMenuItem{
public MacPageSetupMenuItem(){
setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()
+ java.awt.Event.SHIFT_MASK));
}
}
There are two things to note about the highlighted code above. First, because it is Mac specific code we could have hard coded the choice of the menu shortcut mask. This version makes it easier to pull up to the parent class if we need to refactor later. The second issue is that there are actually two masks being specified here. If you look back at the image of the TextEdit File menu you can see that the shortcut for Page Setup requires that you press both the Command and Shift keys while typing the letter P. The values of the masks are powers of two and so you pass in more than one by adding them together. The component pieces of the sum can easily be determined.
|
Related Reading Learning Java |
Cleaning Up the Loose Ends
You can use these three menu item examples from the last section to create the code for the remaining menu items. Once that is done you'll need to create the FileMenu classes for the MacGUI package and for the WindowsGUI package. Here's the MacGUI version.
package MacGUI;
import javax.swing.JMenu;
import commonGUI.*;
public class FileMenu extends JMenu{
public FileMenu(){
super("File");
add(new MacNewMenuItem());
add(new OpenMenuItem());
add(new JMenu("Open Recent"));
addSeparator();
add(new CloseMenuItem());
add(new SaveMenuItem());
add(new MacSaveAsMenuItem());
add(new SaveAllMenuItem());
add(new RevertToSavedMenuItem());
addSeparator();
add(new MacPageSetupMenuItem());
add(new PrintMenuItem());
}
}
Again, make the necessary adjustments for the WindowsGUI version. The final task is to go back and fix the MacJMenuBar and WindowsJMenuBar. We had them create an ordinary JMenu with the label "File". We need to go back and change the code so that we are actually creating a FileMenu object. Here's the fixed version of MacJMenuBar.
package MacGUI;
import javax.swing.JMenuBar;
import javax.swing.JMenu;
public class MacJMenuBar extends JMenuBar{
public MacJMenuBar(){
add(new FileMenu()); // instead of add(new JMenu("File"));
add(new JMenu("Edit"));
add(new JMenu("Format"));
add(new JMenu("Window"));
add(new JMenu("Help"));
}
}
Summary
In this article we tuned a Java application so that it could meet the expectations of two disparate audiences on their home platforms. The application still looks much like a Windows application when run on a Windows machine and now it looks much more like a Mac application when run on a Mac. A combination of using System properties and a minimal amount of parallel code improves the user experience. The next step is to add Mac-specific functionality such as an About Handler--but that's another article.
Daniel H. Steinberg is the editor for the new series of Mac Developer titles for the Pragmatic Programmers. He writes feature articles for Apple's ADC web site and is a regular contributor to Mac Devcenter. He has presented at Apple's Worldwide Developer Conference, MacWorld, MacHack and other Mac developer conferences.
Read more Java Programming on the Mac columns.
Return to the Mac DevCenter.
You must be logged in to the O'Reilly Network to post a talkback.
Showing messages 1 through 11 of 11.
-
thinkfree.com
2002-09-28 19:35:39 winstonford [Reply | View]
I was getting frustrated with Word and Excel's bloated export to html results and so checked out thinkfree. The jvm on ma g3-400 powerbook is a little slow to be an everyday app, but the html export of .doc's is much cleaner, and there are some cool things in the file navigation dialogue when saving.
-
Write Twice, Run Anywhere
2002-09-22 18:50:11 anonymous2 [Reply | View]
Daniel
Your Java instruction in every case has been very helpful and I always look forward to your next tutorial. I created the Write Twice, Run Anywhere program in Project Builder on the Mac and wanted to comment on a few things.
1) When I compiled and ran the program in your first example (e.g. before the Arrrg!), the menu was not on the frame itself, it was where it was supposed to be (Arrrg - not!)???
2) I realized that creating a New Group in Project Builder does not create a new directory folder. However, I was able to create folders in the directory (MacGUI, WindowsGUI, commonGUI) and then use Show Info to change the classpath.
3) Although the program compiles, I haven't been able to build the application and I'm wondering if the following method could be the culprit (needs an " if "??). The log is referenced below. Thanks again for the tutorial instruction.
private JMenuBar getCorrectMenuBar(){
System.setProperty("com.apple.macos.useScreenMenuBar","true");
return new MacJMenuBar();
} else return new WindowsJMenuBar();
}
[LaunchRunner Error] MainFrame.main(String[]) threw an exception:
java.lang.NoClassDefFoundError: commonGUI/OpenMenuItem
at MacGUI.MacJMenuBar.<init>(MacJMenuBar.java:8)
at MainFrame.getCorrectMenuBar(MainFrame.java:17)
at MainFrame.<init>(MainFrame.java:10)
at MainFrame.main(MainFrame.java:23)
at java.lang.reflect.Method.invoke(Native Method)
at com.apple.buckyball.app.LaunchRunner.run(LaunchRunner.java:82)
at com.apple.buckyball.app.LaunchRunner.callMain(LaunchRunner.java:44)
at com.apple.buckyball.app.CarbonLibApp.launch(CarbonLibApp.java:67)
-
Code correction --
2002-09-23 09:51:41 Daniel H. Steinberg |
[Reply | View]
Thanks for your note. Although I like a lot of what Apple has done, I am not a fan of Project Builder for Java development and don't use it. I'm guessing from your first issue that you created a new Java Swing project using Project Builder. When you do this, properties are set for you and the MRJ class files are linked without you knowing where they are.
As for item (2), that's one of the things I don't like about PB. I want there to be a correspondence between the directory structure and the packages. I agree with your comment, but wish it didn't require extra steps. The file management is almost like the iApps where you have playlists on iTunes and Albums in iPhoto. Again, if you like PB for Java programming, that's great. It is free and provides everything you really need.
I'm sorry for the error that led to your question (3). There is an entire line missing from the code. The original version of the code was this.
private JMenuBar getCorrectMenuBar(){
if (System.getProperty("mrj.version")!=null){
return new MacJMenuBar();
} else return new WindowsJMenuBar();
}
The corrected version of the code should have just inserted a line into this code -- I'm sorry for the mistake. Here's the corrected code.
private JMenuBar getCorrectMenuBar(){
if (System.getProperty("mrj.version")!=null){
System.setProperty (
"com.apple.macos.useScreenMenuBar","true");
return new MacJMenuBar();
} else return new WindowsJMenuBar();
}
The only addition is the System.setProperty() method call. Thanks again for catching this error. Sorry for the inconvenience.
Daniel
-
Code correction -- article has been fixed
2002-09-24 11:20:47 Daniel H. Steinberg |
[Reply | View]
Thanks again for your note -- the code has been corrected in the article.
-
A note to keyboards on laptops
2002-09-18 21:31:19 anonymous2 [Reply | View]
Get a Japanese keyboard! Alle japanese keyboards have the CTRL key next to the "A" key (maybe there are more UNIX geeks here??? ;-)
And yes, they also have roman letters written on the keys and the layout is a slightly modified US keyboard layout.
-
Apple Laptop Keyboards Unsuitable for Unix Users
2002-09-18 02:07:17 anonymous2 [Reply | View]
Apple laptops are effectively unusable for unix users.
I am a long-time Unix user. That means I need to have the Ctrl key to the left of the A key. This is a genuine need, not merely a want; it is based upon ergonomics. The Ctrl key is heavily used in unix, and it must be easily accessable. It cannot be off in the lower left corner of the keyboard where it is difficult to get at, and where it distorts the position of your left hand such that you can't easily type other keys while holding the Ctrl key down.
Apple desktop keyboards are now all USB. They are all OK. The CapsLock key can be re-mapped into a Ctrl key.
Unfortunately, even in this modern age, all Apple laptops have built-in ADB keyboards. The ADB keyboard is broken-by-design. It is, in general, not possible to remap the CapsLock key into a Ctrl key.
There are some exceptions, but they are horrible kludges. They are
horrible kludges because the original design of the ADB keyboard was a horrible kludge. The correct solution would be for Apple to re-design their laptop motherboards to use built-in USB keyboards. This hasn't happened yet. If you run Linux, use Debian's solution. For Mac OS X users, uControl works. There are no solutions (that I know of) for either NetBSD or OpenBSD. Please note once again that the "solutions" above are in fact kludges, because of the original bad design of the ADB keyboard.
Apple is (currently) ignoring Unix users! This is not merely speculation on my part. In an on-going email exchange I am having with an Apple employee (whom I won't name) in their marketing department, the Apple marketing person directly stated to me that Apple was catering to their historic Mac customers, and is purposely ignoring the Unix market. He also claimed that Apple would soon start paying more attention to the Unix market. I won't hold my breath. Apple has been ignoring Unix users for more than 10 years. I expect that trend to continue. (Also note that my Apple contact indicated that Macs would never ship with a 3-button mouse, even though Apple intended to port almost all X-window software and deliver it either on a CD/DVD or installed directly on each Mac's hard drive. How Unix friendly is a 1-button mouse with X programs that often require 3 buttons?)
Apple has now lost two opportunities to sell me hardware. I really wanted an Apple laptop for their superior battery life, and for the PowerPC with Altivec CPU. (The Altivec is vastly superior to the x86 line for DSP.) Because I can't live with the broken-by-design built-in ADB keyboard in all Apple laptops, Sony and IBM sold me laptops instead. If Apple fixes this problem, they will sell me a PowerBook next year; if they don't, I'll still be running OpenBSD on x86 hardware, and wishing I could use a Mac.
-
Come on...
2003-06-27 08:49:24 anonymous2 [Reply | View]
Just press the ctrl key wherever it is and get on with your life.
There are other things in life to worry about, like the lack of a 2nd mouse button on the inferiour Mac mice. -
Oh waaaaaaaah
2003-04-27 17:40:43 anonymous2 [Reply | View]
I've been a unix developer for 20 years now. Unix is an amazingly adaptable OS - but as a roving contractor I can't ever be bothered to take the time to customize my local setup. I just use whatever shell/gui/keyboard/editor (typically VI) is there.
Instead - I just learn to be flexible. I am able to simply note the location of the control key and use it for the duration of the session.
Perhaps I'm gifted. More likely you're a whiner.
-
jEdit
2002-09-09 11:09:54 anonymous2 [Reply | View]
I think jEdit http://jedit.org/ is a good example of a Java app that gets a lot of things right on Mac OS X. It's not perfect, but much better than most Java apps I've seen.
-
Apple's notes to Developers on Switching
2002-09-09 08:22:26 Daniel H. Steinberg |
[Reply | View]
I should have linked to this article on Apple's site on notes for Windows developers coming to Aqua. An article this morning on






