Sep 26 2014
There was a big delay since the first issue, but I am back now and have gathered a few more useful tips and examples. Hope you will find them useful!
List of tips:
- Java FX browser in Swing application
- JDK8 lambdas and Swing
- Using hotkeys
- Component isValid method
Java FX browser in Swing application
As you might already know – Java FX provides a decent set of new features and components on top of the common ones which are actually pretty awesome, the most awesome one is the new browser engine that fully supports newer HTML and CSS versions and can actually render any modern websites.
And it is a known fact that there was a new Swing component introduced after the Java FX 2.0 release to support Java FX components integration into your Swing application – JFXPanel. It has some nasty bugs in older versions of JDK 7, but now it works pretty well and I wanted to use it in one of my Swing projects to display some locally hosted website.
After including the browser as displayed in the small tutorial here:
I have tested it for some time and found out just one issue – but a critical one – browser would stop working every time it is readded onto some container.
Since I was using it inside of WebDocumentPane it was readded onto the tabbed pane after any tab drag operation and, as a result, disappeared without even saying anything into log. Debugging the case didn’t give me any result, so I headed to forums to see if there is any solution to this pretty obvious bug.
What I found actually helped me to understand the problem – the cause of this issue was the Java FX Platform behavior. It would automatically perform exit and, as a result, would destroy all Java FX components when there are no visible Java FX components/windows left. So that was exactly the case when I removed my single browser from the WebDocumentPane while drag is performed.
There is also a workaround available in the newer Platform version:
Shortly – this will force Platform to exist ONLY when you ask it to, it won’t do that automatically anymore.
Since adding this line of code browser is working perfectly on all platforms where I have tested it (some Win, Ubuntu & Mac OS X versions).
And by the way, you might also want to shutdown the Platform manually on exit since you have disabled its default behavior:
JDK8 lambdas and Swing
I am sure that almost everyone have already checked out the new feature added in JDK8 – lambda expressions. First expression might not be the best, but believe me – you will love lambdas when you will start using them in your own application. Its not just about “shortening” the code, it is about code readability overall and sometimes even performance improvements.
After working with two big Swing projects based on JDK8 I have made a few useful improvements to WebLaF which will help you to improve your code experience.
As you might know – lambdas are based on functional interfaces which are basically interfaces with just one abstract method. Yes, there are some complex cases, but let’s put those aside for now. Working with Swing is mostly about creating the UI and listening to its various events using listeners or adapters and doing various stuff in response. Those listeners usually have more than one abstract method and in that case they cannot be converted into lambda expression.
I think everyone saw the official code examples where ActionListener was top-1 functional interface example for Swing, but there are a lot more listeners which aren’t that simple and can’t be used in that way which is pretty sad. So my idea was to provide more additional methods with function interfaces to simplify usage of those listeners in Swing components. Just look at the MouseListener or KeyListener – they have lots of methods but in most cases you need only one or two to perform desired actions.
WebLaF itself is still developed under JDK 1.6.0 update 30, but I can add functional intefaces and methods for them and then use them in another project under JDK8 which is pretty awesome. And the result is really amazing. Here are a few small code examples of old and new ways of coding I have used:
For understandable reasons these methods aren’t available in default Swing J-components, but they are available in Web-components implementing various WebLaF method-interfaces. Here are some of these method-interfaces where you can find complete list of methods using custom functional interfaces:
I will be extending this list with time to simplify other actions usage in various components.
As you might have noticed from the previous examples – I am using Hotkey and HotkeyData classes in various cases, for example when I have to deal with KeyEvents. These two classes were written long ago and went through a lot of refactoring and improvements and proved their usefulness in a lot of cases.
Hotkey.java contains a large set of predefined HotkeyData instances for various widely used hotkeys such as CTRL_C, ALT_TAB, ALT_F4 etc. This set should be sufficient for almost any possible case in desktop applications.
HotkeyData.java contains all data required to handle single hotkey within the application. Basically it is three general modifiers – CTRL, SHIFT and ALT and key code. All Hotkey class constants are simply HotkeyData instances filled with appropriate values added to simplify HotkeyData usage.
Why did I use this instead of working with Swing KeyEvent? Because it is not convenient and takes a lot of additional coding in some cases which increases the possibility of making some hardly noticable and annoying mistakes in the code. Also I had to create some universal hotkey information storage for WebLaF’s HotkeyManager to handle custom hotkey events.
Take a look at some new-style VS old-style code examples:
Using Hotkey with customized WebLaF methods won’t just reduce the size of your code but will also reduce the chance of making mistakes when declaring hotkeys. You might have noticed that in the first old-style example I was also checking whether “!e.isShiftDown () && !e.isAltDown ()” or not. This is required to filter out this event in case user presses for example CTLR+SHIFT+ENTER hotkey. This is automatically checked within HotkeyData which simplifies your code even more and makes it readable.
As mentioned before – HotkeyData is also used within almost all HotkeyManager methods. Here is a small example of registering global application hotkey and its action:
So basically HotkeyData can be used as a universal hotkey information for any part of your application.
Component isValid method
Even with such advanced and intelligent IDEs for development we have nowadays we can still easily mess something up and then spend hours to debug the issue caused by just one simple line of code. I have encountered one of such issues just a few days ago and spent almost an hour to narrow it down and find out the source and I wanted to share the small investigation I had there.
I was working with a large data editor application which uses WebDocumentPane as a base for opened documents of any kind – a simple text or image file, java code, css style, UML diagram etc. At some point I have restarted the application and noticed that WebDocumentPane’s tab content is not displayed. It was there just a few restarts ago and I didn’t change anything in that particular editor so that was really weird.
After some debug I found out that content is actually there but simply… not painted for some unknown reason. My guess was that I have messed something up in the abstract editor class, but that guess was wrong since some of the tabs were still displaying correctly.
I have tried to debug painting methods, but those were working as intended as well. I even tried to launch editor’s content separately – it displayed properly. So in the end – the issue was somewhere inside of the abstract editor but I had no idea what it could be.
When my “guess list” was empty, I started to remove parts of editor code to see when it will be back to proper painting. And I finally found the source of this issue, it was a simple method written to validate editor’s content:
When I added it (with default returned value == true) I didn’t notice that it have silently overriden similar component’s method which checks whether component is correctly sized and positioned. So that “true” value I have returned in most cases simply disabled component’s proper positioning and display.
In conclusion I would say that it is usually almost impossible to avoid such issues unless you know about method existance or if you are lucky enough to notice small override mark in IDE until you leave that part of code:
Hopefully this wasn’t too boring and casual.
Not too many screenshots today, though these are all real cases without doubt.
If you have any questions or requests – feel free to comment or contact me anytime.
By the way, next issue will contain some interesting tips about components customization and usage.
Thanks for reading this article and stay tuned!