Hacking on GraphHopper - a Java road routing engine. Peter has posted 62 posts at DZone. You can read more from them at their website. View Full User Profile

Spring Rich Client - Part 2

07.03.2008
| 14488 views |
  • submit to reddit
  

Views …

Hopefully I can create a next blog entry about the docking framework MyDoggy and the integration into SpringRC. Now it works like a charm - try it out! (see resources).

Today I will show what you can apply to all ‘component managers’ that are integrated in SpringRC.

First: there is one application per virtual machine. But there could be one or more ApplicationPages (JFrames) with several views (center, north, south, …). In our case (MyDoggy) there is only one ApplicationPage.

Normally you want to have more than one component per start-up page. To change this add the following xml to the application-context.xml:

<bean id="aLotOfViews" class="org.springframework.richclient.application.support.MultiViewPageDescriptor">
        <property name="viewDescriptors">
            <list>
                <value>view2</value>
                <value>initialView</value>
            </list>
        </property>
</bean>

And change the startingPageId in the lifecycleAdvisor bean to aLotOfViews. With the upcoming MyDoggy 1.5.0 enabled we can get this nice layout, which will be automatically saved(!):

… and more!

If you want to use custom components: just add them! I created a custom component with the open source Matisse GUI builder integrated in NetBeans. Here is the code how you can put this component into SpringRC:

public class CalculatorView extends AbstractView {
    protected JComponent createControl() {
        JPanel panel = getComponentFactory().createPanel(new BorderLayout());
        panel.add(new CalculatorPanel()/*created with Matisse*/, BorderLayout.CENTER);
        return panel;
    }}

To add this view to the startingPage do (aLofOfViews already references to this bean, so no changes are necessary there):

<bean id="view2" class="de.timefinder.core.ui.mydoggy.MyDoggyViewDescriptor">
        <property name="viewClass" value="de.timefinder.core.ui.CalculatorView" />
</bean>

One thing you have to know is: How to translate keys within this ‘external’ CalculatorView?

In Matisse do:

  1. Click the button, where you want to translate the text
  2. Then - in the property panel on the right side - click on the [...] button
  3. Select “Resource Bundle” instead of “Plain Text”
  4. Use the messages.properties file for the bundle name
  5. Insert the appropriate key (defined in messages.properties)
  6. Use the following line to get the value (click on the “Format…” button) Application.instance().getApplicationContext().getMessage(”{key}”, null, null)

For all of the following components it is easier: do 1, 2, 3 and insert the key! This could be the new slogan for Matisse ;-)

Now some more I18N. For example you want to display: “Result of $number!” you should use the following line in message.properties:

calculatorPanel.title=Result of {0} !

and get the formatted string via

Application.instance().getApplicationContext().getMessage("calculatorPanel.title", new Object[]{result}, null);

Another small point could be the ugly output of the standard java 1.4 Logger. We will now change the two-lined logging output into a one-lined. Actually this is a one-liner if you look for yourself into the resource section for the TFFormatter class:

java.util.logging.Logger.getLogger("de.timefinder").getParent().getHandlers()[0].setFormatter(new TFFormatter());

Tasks

In Swing you can use the Swing ProgressMonitor, but in SpringRC you should use the integrated ProgressMonitor to indicate the current progress of a task in the bottom right corner of the page:

With the factorial view of my example you can calculate, yes, factorials. I tried “50 000″ and the calculation took nearly the same time as adding the number to the JTextArea …

So, use the ProgressMonitor in combination with the SwingWorker (I grabbed it from jdesktop, because the SpringRC’s Swingworker uses a FutureResult class and I couldn’t find it!? Where is an “edu.oswego”-jar?)

Now you can use the following code to execute a long running task:

ApplicationWindow aw = Application.instance().getActiveWindow();
final ProgressMonitor pm = aw.getStatusBar().getProgressMonitor();
String str = actx.getMessage("calculatorPanel.startTask", null, null);
pm.taskStarted(str, -1);
SwingWorker sw = new SwingWorker() {
        BigInteger resultLong = BigInteger.ONE;
        //protected Object construct() in SpringRC's SwingWorker!
        protected Object doInBackground() {
            // now my long task and the progress indication
            for (int i = 2; i <= fac && !pm.isCanceled(); i++) {
                pm.worked(100 * i / fac);
                resultLong = resultLong.multiply(BigInteger.valueOf(i));
            }
            return resultLong;
        }
        //protected void finished()
        @Override
        protected void done() {
            // all of the following code will be called on the Event Dispatching Thread
            if (pm.isCanceled()) {
                output.setText("Canceled");
            } else {
                output.setText(resultLong.toString());
            }
            pm.done();
        }
    };
    //sw.start();
    //sw.clear(); // reuse would be possible with SpringRC's SwingWorker!
    sw.execute();

Conclusion

SpringRC offers us - as client-side-programmers - a bunch of powerful utilities to build our application fast and scaleable. Some parts are well documented; some parts not. But I think with relaunching the project in October ‘08 (hopefully!) as Spring Desktop it will get a lot of support from even more users and maybe from the company SpringSource itself. Hopefully then the documentation will be better…

The most important point for me is that SpringRC is ‘only’ a sweat jar collection and not a layer between me and Swing.

Another point is that SpringRC uses dependency injection and NetBeans RCP uses the service locator approach e.g.
SomeInterfaceImpl impl = Lookup.lookup(SomeInterface.class).
instead of the setter injection in the very first example for SpringRC.
For others this could be one more argument against NetBeans RCP (not for me …)

Resources

  • Another older, but very good tutorial is located here.
  • Maybe it is interesting to know: in the updated version of the book Spring - A Developer’s Notebook the last chapter 9 is about the Spring Rich Client Project (author was Keith Donald).
  • Here you can find part 1.
  • Here you can download the project without the jars included in the SpringRC’s download (It is a NetBeans 6.1 project, so you can simply copy all jars of SpringRC into the lib folder and open the project with NetBeans. Then resolve references via right click or change the references directly; in nbproject/project.properties).

From http://karussell.wordpress.com/

Published at DZone with permission of its author, Peter Karussell.

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

Tags:

Comments

Geertjan Wielenga replied on Thu, 2008/07/03 - 2:28am

Thanks again for this info, I'm learning a lot from it. However, I want to comment on this paragraph:

The most important point for me is that SpringRC is ‘only’ a sweat jar collection and not a layer between me and Swing. This is one of the reasons I cannot use NetBeans RCP: with NetBeans you have to learn new stuff (from ground up) and you should forget nearly all things you learned for Swing. Okay, someone will argue that you can even use Swing directly (like JOptionPane.showMessage) but this is not the recommended way of doing things within NetBeans RCP.

 

I like Spring RCP a lot (and am working on a second part to "Getting Started with Spring RCP", which should be published on Javalobby either today or tomorrow), but to say that with NetBeans RCP you "have to learn new stuff (from ground up) and you should forget nearly all things you learned for Swing", is simply untrue. It is 100% false, in fact. You can use Swing as much as you like. Yes, you can use JOptionPanes, though NetBeans RCP offers its own alternatives, you are right about that. However, similarly, with Spring RCP you can continue using the standard Swing dialogs, even though Spring RCP has its own alternatives that it recommends you use. That's great isn't it, both offer additional Swing components. Not bad in either case. I must say that I'm spending the same amount of time learning Spring RCP as I did when I started learning NetBeans RCP.

The real difference between them is that NetBeans RCP is modular, letting you create applications that can be extended via plugins, while Spring RCP doesn't let you do that. Nothing wrong with that. It only means that NetBeans RCP is more suited to very large applications than Spring RCP is. It would be completely impossible, for example, to have created NetBeans IDE on top of Spring RCP. (Plus, I can create my own independent plugins for any application based on top of NetBeans RCP... but how would I create a plugin for the application you are building in this series of articles? And how would you install that plugin into your application?) Since NetBeans RCP is modular, it was perfect for NetBeans IDE, since the IDE is created by many different people in an extremely distributed environment, so that a modular approach fits very well with the distributed workplaces, as well as resulting in very clean code (i.e., no spaghetti code across modules). Therefore, I believe Spring RCP is closer in intention to JSR-296 than it is to NetBeans RCP (actually, it is called "NetBeans Platform") and Eclipse RCP.

Peter Karussell replied on Thu, 2008/07/03 - 5:34am

Hi Geerjan!

[quote]

but to say that with NetBeans RCP you "have to learn new stuff (from ground up) and you should forget nearly all things you learned for Swing", is simply untrue. It is 100% false, in fact.

[/quote]

Hmmh, yes. But as I was using NetBeans RCP 5

I was lost in the new API (no books were published). And I had the feeling that I should use the API to get no bugs etc.

Sorry, I should have marked it with my personal feeling. Not as a fact. I am very sorry about this, because I love NetBeans and I don't want bash against it.

[quote]

I must say that I'm spending the same amount of time learning Spring RCP as I did when I started learning NetBeans RCP.

[/quote]

My personal experience :-) was completely different here. Very quick results with Spring RC and no bugs. With NetBeans I got some strange bugs that I even didn't see in the IDE.

I must say that I all my experiences are possible out of date like my example:

http://genvlin.berlios.de

Please see the Media Zone to try it and the Download Zone to test it and to get an idea of what I mean.

Harris Goldstone replied on Thu, 2008/07/03 - 6:52am

So apps created on the Spring RCP are not pluggable?

Steven Baker replied on Thu, 2008/07/03 - 5:37pm

sometimes i miss when people hard coded things...

it was a simplier time...

Geertjan Wielenga replied on Fri, 2008/07/04 - 2:18am

Peter, the stuff on http://genvlin.berlios.de/ looks very interesting. I will take a look at it.

Richard Osbaldeston replied on Fri, 2008/07/04 - 9:07am

Does Spring RCP have support for a multiple-document interface? (think MS Word >2003). I mean can I have more than one instance of my application and it's classes running in the same JVM. Just wondering how it resolves which action 'belongs' to which application instance in this kind of scenario. Pet question as JSR296 fell sort on this as it also had a similar  getApplication()/getApplicationcontext() as a singleton.

Peter Karussell replied on Fri, 2008/07/04 - 3:42pm

[quote] Does Spring RCP have support for a multiple-document interface? [/quote]

Yes. You can duplicate the application.

[quote] Just wondering how it resolves which action 'belongs' to which application instance in this kind of scenario.[/quote]

Yes, thats right. Not an easy task. I will ask the developers.

[quote] sometimes i miss when people hard coded things... it was a simplier time... [/quote]

... for the developer, but not for the user, I think.

[quote] So apps created on the Spring RCP are not pluggable? [/quote]

What do you mean with "pluggable"?

Harris Goldstone replied on Fri, 2008/07/04 - 3:52pm in response to: Peter Karussell

[quote=peathal][quote]

So apps created on the Spring RCP are not pluggable? [/quote]

 

What do you mean with "pluggable"? 

[/quote]

 

I mean can I create a plugin for an app created on top of Spring RCP? Many modern apps are pluggable and I was wondering if there is some way that that is possible with Spring RCP.

Peter Karussell replied on Fri, 2008/07/04 - 4:05pm

[quote]I mean can I create a plugin for an app created on top of Spring RCP? Many modern apps are pluggable and I was wondering if there is some way that that is possible with Spring RCP.[/quote]

no, I don't think this is possible. Actually there is a discussion about this for the upcoming spring desktop:

http://www.nabble.com/Re%3A--Spring-Desktop--ideas-for-the-Desktop-version-p18229540.html

 

Peter De Bruycker replied on Mon, 2008/07/07 - 6:25am in response to: Peter Karussell

As one of the developers of Spring RCP, I have the following remarks:

  1. Spring RCP applications CAN be pluggable. Spring RCP doesn't include a plugin architecture, but you can use existing solutions for that (OSGI, JPF, roll your own, ...)
  2. There is support for custom progress bar creation in Spring RCP: create a subclass of ProgressSplashScreen, override the getProgressBar method, set your custom colors there, and after creation of the progressbar, revert the changes made to the uimanager:
<code> 
public class CustomProgressSplashScreen extends ProgressSplashScreen {

    @Override
    protected JProgressBar getProgressBar() {
        // colors
        Color backupForeground = UIManager.getColor("ProgressBar.selectionForeground");
        Color backupBackground = UIManager.getColor("ProgressBar.selectionBackground");
        
        Color myYellow = new Color(255, 225, 100);
        Color myGreen = new Color(120, 208, 60);

        UIManager.put("ProgressBar.selectionForeground", myYellow);
        UIManager.put("ProgressBar.selectionBackground", myGreen);

        // create the progressbar
        JProgressBar progressBar = new JProgressBar();
        progressBar.setForeground(myGreen);
        progressBar.setBackground(myYellow);
        progressBar.setBorder(BorderFactory.createLineBorder(myYellow));

        // restore the default colors
        UIManager.put("ProgressBar.selectionForeground", backupForeground);
        UIManager.put("ProgressBar.selectionBackground", backupBackground);
        
        return progressBar;
    }
}
</code> 
This way, you keep all the dirty stuff in one class. 

Hope this helps,

Peter

Peter Karussell replied on Sat, 2008/07/12 - 6:36pm

@peterdb Thanks a lot! This helps a lot.

@richard I asked the question on the dev list. Here is the answer of Jan [*].

This means for evey new instance the xml file is parsed again and all components are newly created.

Regards, Peter. 

 

[*] 

I'll give it a shot:

As a first, I have to inform you that the application that is started
with Spring RCP is a Singleton. So one application per VM. This includes
it's ApplicationServices which are retrieved by the
ApplicationServiceLocator Singleton.

Secondly: there are solutions for MDI in the form of docking frameworks.
Look into the docking module to find out more. This might be what you're
referring to?

As a third: there can be multiple windows per application. As a
consequence of this, the current commands are defined in a separate
context file. This file is re-read when creating a new window in order
to have the correct parent window injected if the command needs to be
window-aware. This allows to have multiple windows, sharing the same
resources, running on one vm and opening different views/dialgs etc...

Thus looking upon this, yes you can do MDI, but no you cannot have
multiple instances running on the same VM. In most cases, the latter
isn't a problem.

Peter Karussell replied on Sat, 2008/07/12 - 6:52pm

Hi peter, I tried it one slight change is necessary to create the progressbar:

JProgressBar progressBar = super.getProgressBar(); 

Peter De Bruycker replied on Mon, 2008/07/14 - 6:24am

Peter,

I updated the code, so you don't have to override the getProgessBar method, but the createProgressBar method.

Thanks for your feedback!

regards,

Peter

Comment viewing options

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