From: Logan Barnett Date: 2008-06-26T06:44:12+09:00 Subject: Re: Can your GUI framework do this? Martin, I'm one of the contributors to Monkeybars, which is our JRuby GUI framework that sits on top of Swing. Here's how Monkeybars handles this: 1. A component consisting of a series of existing components hooked together to act as a single widget In Swing, it is typical to inherit from the component that gets you closest to what you want, and add stuff to there. What you are thinking of is probably a JPanel. While you could inherit from a JPanel, put in the functionality or other components that you wanted, and drop it in where you wanted to use it, we feel there's a better way. Monkeybars uses MVC's delegation of responsibilities to help us out with testing and keep the code more sensible. As such, we felt the best way to approach this would be by providing mechanisms that allow one MVC tuple (your top level window) to nest other MVC tuples (reusable components). This means that controllers communicate with other controllers. Views interact with simple view components directly, but not complicated "partials". Here's your example: An icon widget, that combines a picture and a textfield underneath, with config options to turn either off or size the image, make the text editable, etc" In Monkeybars, the picture/text field grouping would be handled by its own model, view, and controller. This is how you'd tie that in: class MainView < ApplicationView # nesting defines how the component will be added or removed when add_nested_controller or # remove_nested_controller is called. This nesting is one of the simpler ones that just drops in the # component as is. There are more complicated variations that allow you to write all code you want to # determine layout specific arguments, positioning, and layout validation. nest :sub_view => :image_name, :view => :image_name_panel end class MainController < ApplicationController def load @text_image_controller = TextImageController.create_instance # this will kick off the nesting for any nesting with a sub_view of :image_name add_nested_controller :image_name, @text_image_controller end end 2. A component built 'from scratch' atop a canvas, that is, handling its own drawing and event management Since we're using Swing, one could override the paintComponent method on the Swing component used in the view. We've done some of this to render real-time animated graphs with peak bars and graph transitions. We even have it so each graph bar has it's own tooltip text. Here's your example: A speedometer-type dial with a configurable range and tick interval In this case, I'd write my own view component by hand (typically we use a designer for it). A speedometer could be made by using some of the Java2D stuff out there during paintComponent. The needle could be drawn with simple line methods where you specify start and end coordinates. The ticks could be drawn similarly as partial lines. I'd imagine some trig would be involved in the calculations. I would also check to see if any Java folks had already done this, as Java/Swing have been around for a long time. 3. A component combining a canvas and existing widgets I'd want to make the painted canvas widget into a nested controller, so my canvas wouldn't have to care about stomping on other components when it redraws itself. For your example: A box that holds a component and paints a customised border around it This is actually pretty simple in Monkeybars. You can just set the boarder of many (if not all) Swing components. We have a live example using this that you can run via Java Web Start here: http://www.happycamperstudios.com/monkeybars/twit/Twit-and-Twitter.jnlp Here's the snippet that makes the drop-shadow border happen: @image = Java::javax.swing.JLabel.new @image.border = Java::org.jdesktop.swingx.border.DropShadowBorder.new The drop shadow comes from the SwingX library. I'd also like to note that example won us the GUI part of the script bowl competition at Java One (us being JRuby). 4. A container that takes a collection of widgets and lays them out according to some userdefined algorithm There's a ton of ways to do this using Swing using Layouts. Your example: A pure-ruby implementation of a wrapbox (http://zem.novylen.net/ruby/wrapboxdemo.png) This works out of the box just by using a FlowLayout in your container. That can be as simple as this: @main_view_component.layout = Java::javax::swing::FlowLayout.new Some other stuff: Monkeybars has a lot of options for configuring view mappings. View mappings define how data moves from your model to the components in your view, as well as how your components' data moves into your model. One thing that was really important to us in Monkeybars was that for moderate to large projects, a large update method in a controller that intimately knew about the components used made testing incredibly painful. We designed Monkeybars such that most communication between the view and controller is done through the model via the mappings mentioned above. Controllers may also send signals to the view for lightweight or secondary renderings. There is no direct communication, however. This makes testing super easy. You _could_ write Java if you wanted, but we haven't run into occurrences where Java (the language) is needed. You could write all of your designs by hand in Ruby, which is fine. My preferred approach is to use a designer tool, such as Netbeans. Do you really want to lay something like this out by hand? http://www.happycamperstudios.com/monkeybars/charlotte%20interface.png Swing is a part of Monkeybars. We provide some simplified ways to communicate with it (such as implicit event handlers). However, Monkeybars doesn't shield you from Swing. This is both a pro and a con. Swing is a powerful library, but it also has a lot of quirks. Thanks to the folks at JRuby, we have Rubyized methods to all of our Java proxies, and some nice implicit type conversions that make integrating with Java look fairly natural. Monkeybars just makes Swing more palatable, and provides a nice quarantine zone to place all of your Swing code (in the view). You're in JRuby, and that means you're in Java. Java buys you a built- in JIT engine. JRuby's team has told everyone to flag occurrences where MRI is faster as bugs. You also can run your code on any machine with Java installed, and it's hard to find machines without Java. Monkeybars itself is just a jar that happens to be a library. No Ruby installation is needed! Leveraging Rawr you can also wrap your jars in .exes or .app files. You can even use Java Web Start to hand someone a link and the app will auto-install/update and run. You could also integrate Monkeybars into your existing Java app, and start writing all of your new code in Ruby. Java also has a lot of mature code out there, as it has been around for a long time. One personal experience I had was using SNMP. Ruby's SNMP library is great for getting you started, but falls apart when you need to use the more secure SNMPv3. SNMP4J has been around for a while, and is still active. I know a lot of the Ruby community has some bitterness towards Java, but this isn't Java the language we're using here, it's Java the platform. I encourage anyone interested in GUI development to take a peak at our examples and screencasts: http://monkeybars.rubyforge.org/ http://monkeybars.rubyforge.org/tutorials.html -Logan