In Codename One, you traditionally have two choices for designing user interfaces:
- Use the GUI builder (i.e. WYSIWYG)
- Code the UI manually
Although the GUI builder is great, I often find myself coding the UI by hand because it gives me the most control – and it lets me get directly to the code. Of course, you can mix and match GUI builder GUIs with custom code, and I often do. E.g. I’ll set up each Form’s structure in the GUI builder and populate the details in code. Sometimes shifting back and forth between a WYSIWYG context and Java source code can be trying, though.. For some reason, I don’t like shifting gears. When I’m working in code, I like to dive deep in code and look at nothing else but code. When I’m doing desktop WYSIWYG designs, I want to stay in that environment. But I don’t alternate between them terribly well.
Anyhoo… so that’s why I sometimes find myself coding the entire UI in Java.
This has an ENORMOUS down-side, though. For simple UIs with under 5 components, it is manageable. But when you start to get into a complex UI with multiple levels of nested containers, things become something of a mess. And when you go back to modify the code later, it can be difficult to tell the forest from the trees.
A Codename One UI form is very similar to the HTML document model. It defines a tree structure of user interface components. Expressed in HTML, tree-based document models are quite clean and easy to navigate. It is easy to tell which tags are parents of other tags. Not so with Java code. So I thought:
Wouldn’t it be great if I could express my user interface in HTML?
So I set off to do just that.
Requirements:
Before starting on this mission, I had a few requirements in my head:
- The HTML should compile down to Java source code so that it can be compiled just like all of the rest of the classes in Codename One. I.e. The HTML should not be parsed, processed, or converted at runtime. It should be handled completely at compile-time. The reason for this is that we want the build server to be able to optimize the app executables and strip out unneeded classes to keep the app file-size down. It knows how to do this for Java source code, but not with extra HTML files that I might provide to it.
- I should be able to access any parts of the Component hierarchy from Java. Complex UIs require much more than just a simple template structure. You need to be able to attach event listeners, and possibly decorate the components dynamically using Java in ways that just can’t be expressed declaratively. Hence I wanted to make it easy to “access” parts of the generated UI objects.
- I should be able to work with these files seamlessly inside the IDE. I didn’t want to add an extra step when dealing with these HTML UI interfaces. I’d probably forget how to do it when it came time to return to the project.
- No Performance Penalty. I want the UIs to be just as fast as a hand-coded UI.
And so, based on these requirements, I came up with CN1ML – Codename One Markup Language. Which is basically just HTML with a couple of special attributes to help specify how the resulting Codename One UI should look.
How it works
I created a Netbeans plugin for CN1ML so that you can add CN1ML templates directly into your Codename One projects. When you save the CN1ML template, it automatically generates a corresponding Java file with the same name, but different extension. E.g. If I have a CN1ML file at com/myapp/MyForm.cn1ml, it will automatically generate a java file at com/myapp/MyForm.java (which is a Java class with fully qualified class name “com.myapp.MyForm”.
You can then instantiate the form in Java my calling the com.myapp.MyForm constructor – which takes a single “Map” argument that can be used to pass parameters to the template. E.g.
MyForm form = new MyForm(new HashMap());
// Get the root container from the form
Container root = form.getRoot();
What it looks like
Here is a sample Contact Form in CN1ML
The resulting Java source code is long and ugly, but you can check it out here
And here is a screenshot of what this form looks like in an app:
More about CN1ML
If you’re interested in this project, you can read more about it on the GitHub page.
How I Built It
I built the CN1ML parser/compiler in Mirah. This was one of my first Mirah projects since releasing the Mirah Netbeans Plugin last month. So far so good. I can safely say that Mirah is making me more productive than if I had coded this in Java. There are still some rough edges that I’m shaving off, but nothing major. And in places where Java would be a better choice, I can still write those portions in Java in the same project seamlessly.
In fact it was my experience developing the Mirah Netbeans module that gave me some of the inspiration for this CN1ML module. I looked at the problem and knew it could be achieved quite easily using the NetBeans API.
Screencast
I created this screen cast to demonstrate how the CN1ML plugin works.