Introduction

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

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 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 declarative manner and use the results.

So here is example:

/ru/swing/html/example/LoginForm.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="/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 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' tell 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 it's children, placing all <td> contents in appropriate cell. 

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

Now let's bind this form to the controller:

   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);
    }
}

From's markup is loaded and binded to controller using

        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 is to controller, so components who's tag's id is equal to the value of @Bind annotation are injected into the field.
The final result looks like:
loginform.jpg 

Links

The code is located at http://code.google.com/p/swinghtmltemplate/

You can examine documentation at http://code.google.com/p/swinghtmltemplate/wiki/Documentation?wl=en

MigLayout http://www.miglayout.com/ 

TableLayout https://tablelayout.dev.java.net/

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架
新浪微博粉丝精灵,刷粉丝、刷评论、刷转发、企业商家微博营销必备工具"