|
|
||
Elie Levy's BlogCommunity: JavaDesktop ArchivesJavaOne - Extending Swing: Creating your own componentsPosted by elevy on May 30, 2008 at 10:31 AM | Permalink | Comments (5)The JavaOne slides are available now for download. My session on how to extend the swing API creating your own components can be reached at: Extending Swing: Creating your own components Thank you all for the positive feedback you have gave me, it was a great experience! Help? Yes, you can use JavaHelp!Posted by elevy on January 15, 2008 at 10:22 AM | Permalink | Comments (2)Being a server side developer, never had to worry about "help". I mean, about how to provide help to the users of my applications. They were simply just another JSP with ... well that's not what I want to blog about this time. I have been working with client side Java for a while now, learning different interesting things that you can do with Swing. The time came to put together a "help". As I always do, before writing a line of code, I started to google around to find out how others have done it. Other people had to include their help in the rich Java client applications at some point right?. I found a project called JavaHelp. I started reading about it. All I could find was extremely old. All the documentation seemed to be outdated. I wondered, is this project still alive? is this the way to go? I continued doing more research, and I decided I had to give it a try. I downloaded a open source authoring tool, which did not end up being really good. That's why I will not bother mentioning it in here. Continuously reading any documentation I was able to find, encountered some Java code on how to call the JavaHelp system. Finally, got it to work. Then, discovered that you can generate indexes for including the search capabilities. And you know what? it works great!!!! As I mentioned before the documentation was not really good. To get started, just create your content in HTML. Use a page per section of your help. Then you need to create some configuration files to define how the table of contents is going to be structured, and what are the views that you want to include. Here is what I did: 1) Created the helpset definition file: master.hs <?xml version="1.0" encoding="ISO-8859-1"?> <helpset> <title>reis-help</title> <maps> <mapref location="map.jhm"/> <maps> <view> <name>Table of Contents</name> <label>Table of Contents</label> <type>javax.help.TOCView</type> <data>toc.xml</data> </view> <view> <name>Search</name> <label>Search</label> <type>javax.help.SearchView</type> <data engine="com.sun.java.help.search.DefaultSearchEngine">chapters/searchDb</data> </view> </helpset> 2) Create the table of contents in the toc.xml file <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE toc PUBLIC "-//Sun Microsystems Inc.//DTD JavaHelp TOC Version 1.0//EN" "http://java.sun.com/products/javahelp/toc_2_0.dtd"> <toc version="2.0"> <tocitem target="Module_1_help_id" text="Module 1 Label"/> <tocitem target="Module_2_help_id" text="Module 2 Label"/> </toc> 3) Create the mapping file. As you probably saw in the step 2, each of the entries in the table of contents references the documents with ids. Those ids are defined in the mapping file that references the real file. Here is a sample one: <?xml version="1.0" encoding="ISO-8859-1" standalone="no"?> <!DOCTYPE map PUBLIC "-//Sun Microsystems Inc.//DTD JavaHelp Map Version 1.0//EN " "http://java.sun.com/products/javahelp/map_1_0.dtd"> <map version="1.0"> <mapID target="Module_1_help_id" url="chapters/3. module1Help1.html"/> <mapID target="Module_2_help_id" url="chapters/4. module1Help2.html"/> </map> 4) Create the index (only if you want to use the search, which I recommend). run: jhindexer chapters Where chapters is the directory where you have your content. It will go recursively through the directory structure and index all the files. Note that jhindexer has to be in the PATH env variable. It is installed at the bin directory of the JavaHelp distribution. That's it! Now all you have to do is call from your Java code the help component. All the documentation I found uses the broker to create the JavaHelp component. It is like a level of indirection between your code and the code that creates and opens the JavaHelp dialog. The problem is that you don't have control over the dialog it generates. You can not set the icons, you can not get to the GlassPane if you want to do something fancy there. I did a little bit of scanning in the source code (open source advantage!) and found that there is a class called JHelp. It is a Swing component that does everything you will need. Here is my Java code that opens the JavaHelp window:
String pathToHS = "/master.hs";
try {
hsURL = MainFrame.class.getResource(pathToHS);
hs = new HelpSet(null, hsURL);
} catch (Exception e) {
e.printStackTrace();
return;
}
JHelp jHelp = new JHelp(hs);
JDialog dialog = new JDialog(this, "Help", true);
dialog.add("Center", jHelp);
dialog.setSize(new Dimension(950, 700));
dialog.setLocationRelativeTo(null);
dialog.setVisible(true);
That should do it for you too.There are others things I read about that I haven't tried. You can merge different help files dynamically. In this way the user can to install some modules at this time, then later when the other modules are downloaded/installed you can merge dynamically the help for those new modules. Power-N ArchitecturesPosted by elevy on September 21, 2007 at 07:28 AM | Permalink | Comments (0)Early in the dot com boom era, a lot of companies implemented the popular portals. Those portals allowed us to "integrate" multiple applications together into a single screen. I write "integrate" between quotes, because there was nothing really integrated, it was just that the set of applications were displayed in the same screen. The reason for the low level of integration was not because of lack of need, or lack of will. It was primarily because the applications at the time were written to produce data mixed with the rendering information, loosing all the semantics of the "data" that was being produced as a result of a request from the clients. With the services and technologies that are available today I see a completely different future. The ability to create a Rich Client user interface, with most of the benefits that a Thin Client offer, is an amazing technological resource. Think about it for a second. You can create a Rich Client application, that has zero maintenance cost. It is downloaded from the web, it runs on your client machine, and when there is a newer version, it downloads automatically an update (auto-update). For those of you that haven’t have the exposure to it, take a look at Java WebStart. Adding to that we have lots of "backend" services sitting on the web, that can be easily accessed (i.e. google base, etc) and integrated, and semantically integrated. These resources (technologies + services) give birth to what I am calling power-N architectures. We can write a Rich Client application that accesses M * N-Tier services on the Web, integrate the data that the services have, and provide a really powerful tool for the end user. On many cases, as an application/service provider, writing the client application is not going to be enough. Most likely you will still have to provide your own services that provide an extra touch to make your application really unique, but I claim that most of the services that you would need are out there, just waiting to be integrated. There are 2 fundamental differences with the approach I am presenting here. Distribution of Tasks The first one, is using a Rich Client interface that directly accesses the services that are distributed across the network. This is a very important difference. You are having all the advantages of a truly distributed application. Specially scalability and high availability. With the old model, all the services were tunneled through one server that acted as a proxy for you application. With JavaScript, AJAX, and all those technologies you really have no choice but do something like that. It would be extremely complicated to write an application in AJAX that goes to multiple services, and merges the data in an intelligent way. Not the case for full rich client java applications. In this scenario, having your server down, means your application is fully down. In the Power-N architecture, the clients are more independent of the backend availability. If one of the services is down, that only means that the areas of the application that depend on that service is down. But the user can continue using the rest of the services without a problem. I will not write about Scalability, I think it is obvious. Integration The second fundamental difference is Integration. With XML, and the semantic web technologies, we can write application that truly integrate different services. Here I am not talking about just presenting different unrelated information in the same screen. I am talking about real integration. Specialized Browers What will end up happening is that these Rich Client applications distributed across the web, are going to be sort of specialized browsers, that will access and integrate different web services, and provide rich and unique functionalities that are going to facilitate the life of the users. You can access the reviews of a book in amazon.com, and query wikipedia on that book, find the author and its place of birth, get the geo coordinates and map the location, then go to another service and find how much would be a flight ticket to get there, and on, and on, and on… I am not trying to present here a specific use case of a business that would work. I am just presenting an architecture that is here in front of us just waiting to be exploded into what will be the real new web. Java Dock with a better bouncing effectPosted by elevy on July 27, 2007 at 07:26 AM | Permalink | Comments (10)In my last blog I explained how I built a Dock bar using the Timing Framework and the Glass pane. This one is a continuation, where I explain briefly a slight improvement on the bouncing effect. You can try the new version with Java Web Start: (again jdk 1.6+).Here is the source code under GPL. The improvement is to get the icons to bounce lower and lower after each cycle. I am pretty sure that I could have gone overboard and use some physics equations here. However, I followed the keep-it-simple principle. Instead of having one Animator object that repeats itself 6 times - 3 bounces - I created 3 different animator object. Each one goes from 0 to a different height. Then I used the Triggers available in the Timing Framework for starting the next animator after the current one is finished. I was surprised of the simplicity of the API.
TimingTrigger.addTrigger(animator[0], animator[1],
TimingTriggerEvent.STOP);
TimingTrigger.addTrigger(animator[1], animator[2],
TimingTriggerEvent.STOP);
TimingTrigger.addTrigger(animator[2], animator[3],
TimingTriggerEvent.STOP);
The other improvement I added was that after the bouncing animation is completed, I get the bar to animated into the standby state, instead of what I was doing before, which was to make the glass pane not visible. In this way it has a more smooth transition.
animator[3].addTarget(new TimingTarget() {
public void begin() {}
public void end() {
glass.disolve();
}
public void repeat() {}
public void timingEvent(float arg0) {}
});
Here you can see the disolve method:
public void disolve() {
if ((disolver == null) || (!disolver.isRunning())) {
for (int i = 0; i < iconsOnBar.size(); ++i) {
IconOnBar iconOnBar = iconsOnBar.get(i);
iconOnBar.setMouseLocation(MOUSE_OUT);
}
disolver = PropertySetter.createAnimator(500, glass,
"progress", 0f, 1f);
disolver.setAcceleration(0.3f);
disolver.setDeceleration(0.2f);
disolver.addTarget(new TimingTarget() {
public void begin() {}
public void end() {
glass.setVisible(false);
}
public void repeat() {}
public void timingEvent(float t) {}
});
disolver.start();
}
}
We just make sure that there is no other disolver animation in the works, we update the state of all the icons to be "mouse out" and start the animation. Java Dock (Launch Bar)Posted by elevy on July 25, 2007 at 11:14 AM | Permalink | Comments (15)With the timing framework and the glass panel, you can create almost any UI component. Offering cool and complex behaviors. In this blog I present a version of a launch bar (Dock). Here is a screen shot of it in action:
To give it justice, you should try running the demo with Java Web Start: (again jdk 1.6+).Here is the source code under GPL. The component extends JPanel. That provides the foundation to paint the background and the icons. It has an inner class that is the responsible of the animations as the glass pane on the parent frame. Here is where all the magic happens. In the default conditions, when the user is not interacting with the component, the glass pane is not visible. The Dock component paints the background, which is a shape with rounded corners and using anti-aliasing creating a smooth effect on the edges. It was tricky to get the anti-aliasing working. You probably noticed that it uses a nice gradient. The gradient is cached in a buffered image with the width of the image and just a couple of pixels in the height. In this way we can recreate the entire gradient using less memory, and the painting is a lot faster. An important principle that I try to follow is to keep the code as simple as possible. Not introducing optimizations before I know that it is necessary. In this particular case, I followed the same philosophy, until I saw that the animation was not performing, when I started optimizing the code as I continue describing later in this blog. On top of the background, the component just paints the icons in the order they were added one next to each other. There is a mouse listener, that is waiting for the user to move the mouse over the component. At this time, we make the glass pane visible. And start animating! The glass panel is the one that paints the animations. The trick is to record for each icon it's current state, and the state after the animation. In this way we can calculate its size and location based on how long the animation has progressed. Each icon has an Id which maps to its location in the Dock. When the mouse moves over the Dock, we determine the icon id that the mouse is over. We are going to call it mouseOverId. In the glass paint method we iterate over all the icons. To determine the size of each icon after the transition is completed, we use the Math.abs of the differece between the mouseOverId and the iconId. That gives us the distance between the mouse location and the icon being painted. One tricky thing was to determine the horizontal position of each icon. The solution was to make sure that the entire dock is always centered on the screen, and that the icons are centered in the dock. With that in mind, every time a icon expands or retracts the location of the dock is recalculated, and the icons location in the dock too. It actually works really well. Then we use the timing framework to animate the transition from the previous size to the next size. Using acceleration and deceleration allows the animation to look very smooth. There is another event that we listen. It is the mouse click. In that case we start another animation with the timing framework. This time to simulate a bouncing effect. For that we use a deceleration of 9.8 ~ 10 (gravity!) It looks very real. I just need to make the height of the bouncing lower and lower after each cycle Every icon is appended with the mirror image, using the swingx ReflectionRenderer.appendReflection(...) In the case of the bouncing, we create the reflection, and then append it at a distance proportional to the bouncing effect, to make it look more real. When I finished codding it, it was working great in the demo app (similar to the one that you are seeing in the web start). However, as soon as I tried to integrate it with a more elaborate user interface with lots of windows and components in the background the animation started to be really slow. I discovered a couple of things that I was doing wrong. Hopefully my learning experience will help you not to make the same mistakes: 1) Everytime you create a Graphics object, you need to call the dispose method as soon as you are done with it. 2) When you don't need a BufferedImage anymore, call the flush method Those are 2 things that were sort of surprising to me, comming from the background of server side development, I did not expect that I had to free resources explicitly. I understand that working with graphics is resource intensive and it is extremely difficult, if not impossible to actually leave the gc to do it efficiently for you. 3) Probably the most important thing, when you call repaint from the animation trigger, call it with the clip. Specially when you are working on a transparent glass pane, and there are a lot of components underneath it. The repaint with the clipping area is going to make sure that only the components that are in that area get repainted, not the entire application. Even if your paint method does not take advantage of the clip, you should still pass it by. Fancy JTable Animations, or should I say "Extreme"Posted by elevy on June 15, 2007 at 06:43 AM | Permalink | Comments (10)If you went to the Extreme Makeovers JavaOne 2007 presentation, you probably enjoyed as much as I did the fancy table sorting animations that were presented. I got impatient waiting for them to release their code, and went to write my own. I did not write it exactly as it is presented there, but I followed the same principles. The layout of the cells was done with the GroupLayout instead of the GridBagLayout. I didn't finished the "spanning" effect yet. Here you can download the src under GPL And for those of you that want to see it in action, you can try it now:
(yes, sorry, you need jdk1.6)
Try clicking the column headers to see how the table gets sorted. It is very fancy. After using it for a while, when I click on a table that does not have this effect I feel like it did not sorted the rows!. I can't wait to use this effect in one of my projects. JavaOne: Using the Java Concurrency API and Deadlock Prevention in a RETE Rules Engine to Implement a Pricing EnginePosted by elevy on May 04, 2007 at 11:56 AM | Permalink | Comments (0)The JavaOne conference is coming up next week. I am very excited specially because I will be presenting the BOF session: Using the Java Concurrency API and Deadlock Prevention in a RETE Rules Engine to Implement a Pricing Engine. In the presentation I will be covering how the Zilonis Rules Engine manages concurrency, and how it can be used in an E-Commerce application for determining prices. I will demo the Zilonis Rules Analysis Tool. That tool is implemented using some of the Swing hacks available in the Aerith application, and the UI looks really cool! After the JavaOne I will posting some blogs about the engine, the tools, and the algorithm in general. Also I will update the Zilonis web site, with the latest version, more documentation, and some surprises that I have to keep for after the JavaOne. See you guys over there! Why Java is going to succeed in the client sidePosted by elevy on February 21, 2007 at 06:15 AM | Permalink | Comments (16)When Sun Microsystems released Java back in 1995, the big promise was that it was going to bring profound changes in the way we interact with Web applications. The amazing Applets were going to allow us to write multiplatform rich client applications deployed over the web, that would lead to a reduction of total cost of ownership. Recently, I came to the realization that this is not over yet. It seems like the trend is on AJAX technologies. We are developing rich client applications using HTML, Java Script, and communicating to the server using XML. Those applications are running inside a browser... it sounds way too much like what the Applets of 1995-96 where promising back then. It feels like a Dejavu. How these AJAX applications are being developed? There are different AJAX frameworks or APIs. IMHO, they are all extremely difficult to program with, to debug, and to test. If you take a deeper look into what those projects are doing, you are going to realize that they are reinventing the wheel. I believe that we already have that infrastructure in place, they are just trying to recreate it, and to make things worse, they are using the wrong technologies. I am a firm believer in simplicity. And for sure, compiling into JavaScript is not simple. Java is here today, and it’s making that dream a reality. It is not applets anymore, but Java Web Start. It is not AWT but Swing. I used to think that the Java Client Applications had to have an odd looking UI. If you looked at the early days of Swing, or any of the Swing tutorials, you will find the Metal Look and Feel. I thought as a developer that I was stuck with it, or the best option was to use the platform specific look and feels. BTW those never looked or behaved like the platform in place. Later on, I found the Substance project. It seems like a huge amount of work, but still just out of the box the UIs would look with a very odd color combination selection. Well, I guess that you can customize the colors and make it look better, but I am referring to first impressions here. I am pretty sure, that there is a lot of people who are still as wrong as I used to be. A deeper look into the APIs and the available Look and Feels allowed me to realize that the Java Rich Client Applications can have amazing UIs. You just have to take a look at the the Aerith Java One demo to realize the things that can be accomplished with the Swing APIs, the Java 3D, and the Animation frameworks. It would be nice if someone would go ahead, and package that application into a more reusable framework. Perhaps, I will work on that some day. There is the SwingX project which has a lot of interesting components. There is very little documentation out there, but the code is generally self explanatory. I will write later on some of the components I have used (how I improved the Login framework to allow me to plug the “Waiting with Style in Swing” hack, but that's for another blog...). I hope that the industry realizes everything I am presenting in this blog at some point in the near future, then AJAX will just be a transitory step in the evolution of the Web Applications and Java is going to rule in the client side. | ||
|
|