Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / Swing

Ease Swing GUI Creation with HTML Templating

4.80/5 (5 votes)
24 Nov 2010CPOL2 min read 57.2K  
Shows how to manage swing components in HTML style

Introduction

Creating GUI in Java is rather difficult. Ordinary code looks like:

Java
JPanel south = new JPanel(new BorderLayout());  
south.add(new JLabel(«login»), BorderLayout.WEST); 
south.add(new JTextField(),BorderLayout.CENTER);
rootPanel.add(south, BorderLayout.SOUTH);

Imagine that you have 15 fields... TableLayout and MigLayout ease layout for many fields, but anyway you have to write Java code.

Background

A lot of programmers (especially in Russia) started with Delphi. The cool thing in Delphi is that you don't have to write GUI code at all. GUI markup is located in a separate file and is linked to the app by IDE.

Almost the same approach is used in Jetbrains IntelliJ Idea. The markup is located in .form file and is converted to the Java code by IDE. Also form's (controller's) fields are injected with appropriate components.

Using the Code

My approach is to put all markup into external file and to construct form in runtime with the help of framework. This approach is like IOC pattern — you do not think about managing of form, you just describe it in a declarative manner and use the results.

So here is an example:

/ru/swing/html/example/LoginForm.html 
HTML
<html>
<head>
    <style type="text/css">
        .red {
            color: red;
        }
        .top {
            vertical-align: top;
        }
        #loginForm {
            x-miglayout-column-constraints: [right]related[grow,fill];
        }
        body {
            border: compound (empty 12 12 12 12) (compound (etched) (empty 12 12 12 12));
        }
    </style>
</head>
<body id="rootPanel" style="display: border; width: 400; height:300; 
	border: empty 12 12 12 12">
<table>
    <tr>
        <td rowspan="3" class="top">
            <img src="http://www.codeproject.com/img/login_icon.gif" alt=""/>
        </td>
        <td width="fill">
            <form id="loginForm">
                <p>Login:</p>
                <input id="login" type="text" align="wrap"/>
                <p>Password:</p>
                <input id="password" type="password" align="wrap" />
            </form>
        </td>
    </tr>
    <tr>
        <td>
            <p id="result" class="red"></p>
        </td>
    </tr>
    <tr>
        <td>
            <div style="display: box; x-boxlayout-direction: 
		horizontal; border: empty 0 0 0 6">
                <glue type="horizontal"/>
                <input type="button" text="OK" id="ok" icon="/img/accept.png" />
                <strut type="horizontal" style="width: 6"/>
                <input type="button" text="Cancel" id="cancel" icon="/img/cancel.png"/>
            </div>
        </td>
    </tr>
</table>
</body>
</html>

This is the HTML markup of login form. Every HTML tag will produce some swing component. For example, <body> will produce javax.swing.JPanel.

'display' attribute tells which layout manager will be used in tag's component. 'border' tells that it will be java.awt.BorderLayout.

Every direct child tag is placed in parent's component. Most layout's (BorderLayout, for example) place component using 'align' attribute as constraint. Default constraint for BorderLayout is center, so table will be placed in the center part of JPanel.

Also notice that tag <table> is used. It will produce JPanel, as <body>, but will set TableLayout as layout manager. After that, it will specially handle its children, placing all <td> contents in appropriate cells.

In a similar manner, <form> produces JPanel with MigLayout layout manager.

Now let's bind this form to the controller:

Java
package ru.swing.html.example;
import org.jdom.JDOMException;
import ru.swing.html.Bind;
import ru.swing.html.Binder;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
public class LoginForm {

    @Bind("login")
    private JTextField login;

    @Bind("password")
    private JPasswordField password;

    @Bind("ok")
    private JButton okBtn;

    @Bind("cancel")
    private JButton cancelBtn;

    @Bind("rootPanel")
    private JPanel rootPanel;

    @Bind("result")
    private JLabel result;

    public LoginForm() {

        try {
            Binder.bind(this);
        } catch (JDOMException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        init();
    }

    public void init() {

        okBtn.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                result.setText("Logging in user "+login.getText());
            }
        });

        cancelBtn.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                result.setText("Cancel clicked");
            }
        });
    }

    public JPanel getRootPanel() {
        return rootPanel;
    }

    public static void main(String[] args) throws JDOMException, IOException {
        LoginForm loginForm = new LoginForm();
        JFrame f = new JFrame("Test");
        f.setSize(400, 200);
        f.getContentPane().add(loginForm.getRootPanel());
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setVisible(true);
    }
}

Form's markup is loaded and binded to controller using:

Java
try {
    Binder.bind(this);
} catch (JDOMException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

This call searches for file /ru/swing/html/example/LoginForm.html (as class is named ru.swing.html.example.LoginForm), loads it, builds swing components tree and than binds it to controller, so components whose tag's id is equal to the value of @Bind annotation is injected into the field.

The final result looks like:

loginform.jpg

Links

History

  • 24th November, 2010: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)