Structuring Java code that assembles a UI
I’m dong some GWT coding today, which is a lot like writing Swing. It’s very procedural. Create a new UI element, then call methods on it to set up the state. Even when you do the right thing and split your UI into many Composite classes, you get something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 | StackPanel stackPanel = new StackPanel(); stackPanel.add(new Label("Recently Eaten")); stackPanel.add(new Label("Manual Entry")); stackPanel.add(new Label("Search the database")); DockPanel panel = new DockPanel(); panel.add(stackPanel, DockPanel.CENTER); FlowPanel buttonsPanel = new FlowPanel(); buttonsPanel.add(new Button("Done")); buttonsPanel.add(new Button("Next")); panel.add(buttonsPanel, DockPanel.SOUTH); |
This is really annoying. The order of assembly is important, but it’s also very arbitrary. I’m creating my DockPanel before my FlowPanel, but you should always declare variables in the narrowest scope possible (item 45 in Effective Java). On the other hand, maybe I want to finish referring to my StackPanel, adding it to the parent, before I create my FlowPanel. Also, it’s easy to make a mistake here. I might accidentally add something to the wrong parent container, if the variable names are similar, and there isn’t a good way to test this code aside from inspecting the UI visually.
Maybe Java is just not a good language to express this UI layout, but for now I considered an under-used construct, inline instance initialization blocks:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | final StackPanel stackPanel = new StackPanel() {{ add(new RecentlyEatenPanel(), "Recently Eaten"); add(new ManualEntryPanel(), "Manual Entry"); add(new DatabaseSearchPanel(), "Search the database"); }}; final FlowPanel buttonsPanel = new FlowPanel() {{ add(nextButton); add(doneButton); }}; DockPanel panel = new DockPanel() {{ add(stackPanel, DockPanel.CENTER); add(buttonsPanel, DockPanel.SOUTH); }}; |
This is kind of cool - the structure is certainly more evident in this code. The extra braces define an initializer that is copied into each constructor - see the Sun tutorial. I assume that the code in the initializer block executes after the constructor has finished its work, so we can depend on the add() method having a place to do its work.
The limitations: this creates a subclass, so you can’t use it to initialize fields in a final class. Also, as you see, any variables must be declared final to be used in the initializer block, just like with any anonymous inner class.
Links:
Here’s a clever DSL to build the GUI in a “fluent” way: http://www.pathf.com/blogs/2007/09/expressing-rich/
And a project to use Flex-style XML to configure the layout: http://code.google.com/p/gwt-ui/
1 Comment to Structuring Java code that assembles a UI
Watch out though for memory leaks when using this clever trick. It hit us a while back, http://jawspeak.com/2009/03/10/using-these-anonymous-inner-classes-is-probably-too-clever-for-your-own-good/
Leave a comment
About Me
Tweets
- Man, nothing kills a super bowl bowl party like someone winning the super bowl 1 day ago
- Wow hulu desktop is a great app. Web apps may be improving but they can't keep up. Can't wait till this comes built-in to your TV! 3 days ago
- @bsneade people like to be scared. The media just gives them what they want! 3 days ago
- Help me stop corporate influence over elections. There's a great, easy email form at http://fixcongressfirst.org #fixcongressfirst 5 days ago
- My economic theory: http://twitgoo.com/d4lci 5 days ago
- http://bit.ly/7I4nDl ...well, California is still missing community fish hatcheries and county-subsidized greenhouses. 1 week ago
- iPad is lame. Just another viewer for your iTunes purchases and no innovations in the online experience. I'd rather have a Chrome OS netbook 1 week ago
- Tore my lip when it stuck to a cold popsicle during intermission. It's bleeding a little, which I hope stops before the trombone entrance... 2 weeks ago
- More updates...
Powered by Twitter Tools.
August 20, 2009