Christopher has posted 9 posts at DZone. You can read more from them at their website. View Full User Profile

Native File Dialogs in Swing - An Experiment With DJ Native Swing

03.30.2009
| 21507 views |
  • submit to reddit

Swing has made pretty good progress to look native, nevertheless there is one thing that definitely does not feel native: file and directory dialogs. There are several problems with Swing's file or directory dialog. It is not possible to select multiple files by dragging the mouse, it does not refresh when the list of files is modified externally, files lack their context menu, renaming files and folders is awkward, etc.

Following my recent release of DJ Native Swing 0.9.8, a developer contacted me and asked whether it offers a native file dialog component. I replied "no but I can investigate"... You see, the main difficulty is that such dialogs are natively modal which is an aspect I never had to deal with when integrating components like a web browser.

After a bit of investigation, I eventually managed to bridge SWT's file and directory dialog as shown on this screenshot:

From Swing's point of view, the API is pretty simple. Here is how to create a basic "save file" dialog:

JFileDialog fileDialog = new JFileDialog();
fileDialog.setDialogType(DialogType.SAVE_DIALOG_TYPE);
// This call blocks until the user has selected a file or canceled.
fileDialog.show(parentWindow);
System.out.println("You selected: " + fileDialog.getSelectedFileName());

The file dialog supports multiple selection and extension filters. Here is such an example (an "open file" dialog):

JFileDialog fileDialog = new JFileDialog();
fileDialog.setSelectionMode(SelectionMode.MULTIPLE_SELECTION);
// We want 3 extension filters, and want the second choice (index 1) to be the default.
fileDialog.setExtensionFilters(
new String[] {"*.*", "*.mp3;*.avi", "*.txt;*.doc"},
new String[] {"All files", "Multimedia file (*.mp3, *.avi)", "Text document (*.txt, *.doc)"},
1);
fileDialog.show(parentWindow);
System.out.println("You selected: " + Arrays.toString(fileDialog.getSelectedFileNames()));

The directory dialog API is very similar. Here is a basic directory selection dialog:

JDirectoryDialog directoryDialog = new JDirectoryDialog();
directoryDialog.show(parentWindow);
System.out.println("You selected: " + directoryDialog.getSelectedDirectory());

Of course do not forget to initialize the Native Swing library in your main method:

public static void main(String[] args) {
NativeInterface.open();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// Your application code goes here.
}
});
NativeInterface.runEventPump();
}

At this stage, I would love to hear what you think about it. If you want to try it to see for yourself, you can launch the demo with this WebStart link or download the DJ Native Swing 0.9.9 preview and run the demo. Both show the code too.

Note that DJ Native Swing works on Windows and Linux, but not yet on the Mac.

-Christopher

 

Published at DZone with permission of its author, Christopher Deckers.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Arek Stryjski replied on Mon, 2009/03/30 - 4:57am

The file dialogs looks good however most other components crash because I don't have MOZILLA_FIVE_HOME variable set on my computer (Ubuntu 8.10).

Are you planing to support Mac? If yes will it run on Mac JRE 1.5?

Christopher Deckers replied on Mon, 2009/03/30 - 5:14am in response to: Arek Stryjski

Hi Arek,

> most other components crash because I don't have MOZILLA_FIVE_HOME variable set on my computer (Ubuntu 8.10).

I believe you get a message saying so rather than a crash. In any case, I did not want to make you download a whole XULRunner distrib.

About MAC support, it mainly depends on an SWT bug to be fixed first (you can vote for it!).

-Christopher

 

Radek Jun replied on Mon, 2009/03/30 - 7:33am

Looks pretty good! Would be nice if it be as part of JRE, also works in Mac and all 64bit system variants.

Christopher Deckers replied on Mon, 2009/03/30 - 8:08am in response to: Radek Jun

On Windows and Linux, 64 bit works provided you add the right SWT library. I should have added that to the WebStart descriptor...

-Christopher

Carl Antaki replied on Mon, 2009/03/30 - 9:44am

Great job Christopher. I've been also using SWT's FileDialog on Windows 32/64 and using SWT_AWT but your solution is better. I wasn't able to get the multi-selection FileDialog to resize I guess it's because I'm using SWT 3.4. Your solution also works on Linux. Well done. The only thing remaining is Mac support

 Carl

Christopher Deckers replied on Mon, 2009/03/30 - 12:30pm in response to: Carl Antaki

> I wasn't able to get the multi-selection FileDialog to resize I guess it's because I'm using SWT 3.4

Yes, I think you are right: this works in 3.5M6 as far as I can tell.

-Christopher

 

Jim Wilson replied on Mon, 2009/03/30 - 4:59pm

Very interesting! I'm curious of your opinion on the use of java.awt.FileDialog as opposed to JFileDialog?

I used a plain old FileDialog in my file browser demo for the "browse" button and have been very happy with the results. Thanks in advance!

cowwoc replied on Mon, 2009/03/30 - 9:00pm

Yet another great release by Christopher :)

 

Keep up the good work!

Gili

Christopher Deckers replied on Tue, 2009/03/31 - 2:36am in response to: Jim Wilson

Jim,

AWT FileDialog lacks a few functionalities as far as I can tell. It lacks multi selection and named file filters (i.e. multiple filters with a name, that are shown in the "Files of type" combo on the Windows dialog). Moreover, the AWT FileDialog looks bad under Linux.

Maybe Sun could fill the gap by adding a new mode. In addition to LOAD and SAVE, they could add MULTIPLE_LOAD (multiple save would not make much sense), along with a method called "getFiles()".

And about the filters, they could add "setFilenameFilters(String[] names, FilenameFilter[] filters, int defaultSelectedIndex)"

I think the AWT FileDialog could easily be extended to be useful, but I am not sure whether there is going to be some effort in that area... If some developer at Sun reads this, please consider it :)

-Christopher

steve pan replied on Tue, 2009/03/31 - 5:54am

excellent! I use sw_awt bridge to add the native filedialog to Swing. It seems that the DJ solution is much better.

 

Christopher Deckers replied on Tue, 2009/03/31 - 6:05am in response to: steve pan

Well, I do use the SWT_AWT bridge, but I rely on DJ NativeSwing's integration capabilities to better handle modality and other such aspects. I also try to provide a more Swing-like API.

Jim Wilson replied on Tue, 2009/03/31 - 2:14pm

Thanks for the reply, Christopher.  You're completely correct about the downsides to the awt FileDialog.  It looks atrocious in Linux, seems to reference xorg and not the particular windowing system on top (Gnome, etc).

And you're also right about the lack of support for directory dialogs and file extension or type filtering, both of which are very nice features to have.  I hope you're able to support Macs soon with your swing native dialogs - I'm pretty certain you'd have the best solution out there at that point :) 

steve pan replied on Tue, 2009/03/31 - 11:11pm

This integration is better than embedding a Swing component into SWT apps. I tried to add swing panel to SWT app, but met a lot of  issues (incorrect mouse position, flickering).  It requires too many modifications. 

However, it seems that the location of JFiledialog is always on the right-bottom corner, which is not appropriate for my app.  I tried to change the code, could not find the build script in ver. 0.99. 

Christopher Deckers replied on Wed, 2009/04/01 - 5:23am in response to: steve pan

Hi Steve,

> However, it seems that the location of JFiledialog is always on the right-bottom corner

As far as I can tell, the position is the last position at which the file dialog of your OS was shown.

What OS are you using?

> I tried to change the code, could not find the build script in ver. 0.99.

The CVS version is the one to work with. A checkout from Eclipse is probably the easiest to do.

-Christopher

 

steve pan replied on Wed, 2009/04/01 - 7:40am in response to: Christopher Deckers

Thanks for your replay. I'm using Windows XP with J2SE6 Update 12. I did not use Eclipse, and use Ant to compile my code now. 

The JFiledialog always appears on the bottom-right corner when I open it  the first time. When I drag it and open it again, it does remember the last position and appears in the last place. The final result is: each time I lauch my app, I have to open and drag it once. 

This issue can be reproduced with the demo jar file in  DJ-swing.  However, the JFileDialog location is suitable, and is not a problem for the demo jar file. 

 

 

 

 

 

 

 

 

 

 

 

 

Christopher Deckers replied on Wed, 2009/04/01 - 9:56am in response to: steve pan

Hi Steve,

After another check I think you are right: the position is not the last positionthe first time the demo is run. I will investigate and see if there is anything I can do about.

Thanks a lot for reporting the issue!

-Christopher

 

steve pan replied on Wed, 2009/04/01 - 11:11am in response to: Christopher Deckers

Thanks a lot. I have replaced all JFileChooser in my app with JFileDialog now.This issue is one of the last two things to overcome. Some third-party Swing lookandfeels can not work with DJ-Swing properly, while the standard Nimbus, Windows lookandfeels work seamlessly.

 

 

 

 

 

 

 

Christopher Deckers replied on Wed, 2009/04/01 - 2:32pm in response to: steve pan

Steve,

About the dialog location problem, I made a minor change (a small hack) while waiting for a proper fix. I found there was a more general issue with SWT's handling of dialogs, so I filed these:
- a bug.
- an enhancement.
... which you can vote for!

You can get this updated version here.

> Some third-party Swing lookandfeels can not work with DJ-Swing properly

True, and there is little I can do about it. Native components have the default look of the OS because they are provided by the OS.

-Christopher

 

Jay Huang replied on Wed, 2009/04/01 - 2:38pm

It looks very nice. However, when I tried to use it in my OWN program, I have to include DJNativeSwing-SWTDemo.jar otherwise I get 'NoClassDefFoundError: org/eclipse/swt/SWT' error.  Should the required classes be packaged into DJNativeSwing.jar or DJNativeSwing-SWT.jar  ? Thanks

Christopher Deckers replied on Wed, 2009/04/01 - 3:25pm in response to: Jay Huang

Hi Jay,

You need DJNativeSwing.jar, DJNativeSwing-SWT.jar and SWT3.5M6.jar (look in the lib folder, the Windows version is shipped in the zip). You may need some additional JARs (still in the lib folder) depending on which components and features you use, but for the native dialogs that should be it.

I thinked it somehow worked when you included the demo JAR because it references all the dependencies needed by the demo in its JAR manifest.

-Christopher

 

steve pan replied on Sat, 2009/04/04 - 4:45am

Hi! Christopher,  the hack in Ver 0.99-2009-04-01 works, and the JFileDialog appears in the desired location (center) now. Thanks for your quick solution.

However, I tested the latest ver 0.99-2009-04-01 and found one issue. 

The demo jar file and my app can not launch  sometimes (very frequently)

G:\downloader\orbit\DJNativeSwing-SWT-0-9-9-20090401>java -jar DJNativeSwing-SWT Demo.jar Exception in thread "main" java.lang.IllegalStateException: Failed to find a sui table local host address to communicate with a spawned VM! at chrriis.dj.nativeswing.swtimpl.NativeInterface$OutProcess.createOutPr ocessMessagingInterface(NativeInterface.java:683) at chrriis.dj.nativeswing.swtimpl.NativeInterface$OutProcess.createOutPr ocessCommunicationChannel(NativeInterface.java:482) at chrriis.dj.nativeswing.swtimpl.NativeInterface.open(NativeInterface.j ava:225) at chrriis.dj.nativeswing.swtimpl.demo.DemoFrame.main(DemoFrame.java:229

 

I checked the code, and found that perhaps it is caused by the function

public static String getLocalHostAddress() {

in  DJNativeSwing\chrriis\common\Utils.java. 

When I added the following line before open nativeinterface, the error did not appear again.

System.setProperty("nativeswing.localhostaddress", "_localhost_");

 

best regards. 

 

 

steve pan replied on Sat, 2009/04/04 - 4:50am

deleted

Christopher Deckers replied on Sat, 2009/04/04 - 6:08am in response to: steve pan

Hi Steve,

This is interesting. I would love to know why it is failing, or tweak the getLocalHostAddress() method so that it actually finds a proper address...

Nevertheless, the system property you mention was meant to fix this issue. The problem is that on some misconfigured systems, resolving the localhost can take up to 30 seconds...

Another way would be to use the experimental "-Dnativeswing.interface.outprocess.communication=processio" system property (it sometimes freezes when launched from Eclipse, but seems fine when launched the usual way...). Nevertheless, other features like the flash player would not work if a local address cannot be found.

Note that this is the first time I hear about this problem, si if you have some free time and want to help find a fix, please contact me by e-mail.

-Christopher

 

Rahul Kumar replied on Sun, 2009/04/05 - 3:10am

Hi Chris, It is confusing, where I put my last post for sake of continuation of my dialogue. There seem to be lots of forum. Anyway, I want customize ButtonBarPane, so that forward and back button are not present, but refresh and stop buttons are there. I was tinkering with idea to use reflection for NativeWebBrowser.java (this is package private), creating ButtonBarPane inner class in my custom class and extend JWebBrowser.java Unfortunately I am going no where. Can you please tell me what can be done for this.

Christopher Deckers replied on Sun, 2009/04/05 - 6:02am in response to: Rahul Kumar

Hi,

> Can you please tell me what can be done for this.

The only thing that could be done currently is to hide all the bars and create your own. You would listen to the various events to enable/disable those buttons as I do in the JWebBrowser class.

Another possibility is to change the sources of JWebBrowser to your needs.

> I was tinkering with idea to use reflection for NativeWebBrowser.java

This is dangerous, because you never know in a future release if I am not going to change the whole internal component hierarchy.

In the current code, there is no real access to the internal UI components to customize them. I could think of such API, though I doubt it is generally needed, and when one does it is generally in its own different way. If hiding certain elements makes some sense (like the back/forward buttons), then I could as well add a "setNavigationButtonsVisible(boolean)". In such a case, please let me know what you are trying to do and I would consider that.

> It is confusing, where I put my last post for sake of continuation of my dialogue.

The preferred way to communicate are the project's SourceForge help forum or by e-mail to chrriis at nextencia dot net.

Cheers,
-Christopher

Rahul Kumar replied on Sun, 2009/04/05 - 7:21am in response to: Christopher Deckers

I am trying to put a check box to tick off navigation buttons similar to menu bar check box. Probably you can include me in development of this browser.

Christopher Deckers replied on Sun, 2009/04/05 - 8:58am in response to: Rahul Kumar

Please, send me an e-mail to tell me exactly what you are trying to do, and how you were thinking to implement it.

-Christopher

steve pan replied on Wed, 2009/04/08 - 10:28pm

Hi, Christopher, after some tests,  I guess that the "localhost" issue in my last post is caused by my own error.

In my impression, the NativeInterface will setup a peer VM which is bounded to a given inet address.  If the peer VM was not destroyed completely, in some cases the inet address would be stll in use after crash or exit.  The exception would be reported when the program launched next time and failed to get the inet address. 

I have added NativeInterface.close() explicitly to deconstructor of my app.

regards. 

 

 

 

 

 

 

 

 

 

 

Christopher Deckers replied on Thu, 2009/04/09 - 4:11am in response to: steve pan

Steve,

What troubles me is that the peer VM dies shortly after the first VM is closed. Moreover, a different port is used so I don't see wy it could not access the IP.

-Christopher

cddddd bb replied on Thu, 2009/04/23 - 2:53am

Dear Christopher Deckers: i usr your DJNativeswing in windows that is run , very ok but in linux ,gtk2.1 ,jdk1.7 ,that have the question: can u help me NativeSwing: NativeSwing: (Gecko:4939): Gtk-CRITICAL **: gtk_window_group_remove_window: assertion `window->group == window_group' failed -------------------------------------------------------------------------------------------- java.io.EOFException at java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2571) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1315) at java.io.ObjectInputStream.readUnshared(ObjectInputStream.java:459) at chrriis.dj.nativeswing.swtimpl.OutProcessMessagingInterface.readMessageFromChannel(OutProcessMessagingInterface.java:113) at chrriis.dj.nativeswing.swtimpl.MessagingInterface$2.run(MessagingInterface.java:329) Failed messaging: NativeComponent$CMN_destroyControl()

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.