使用WindowBuilder辅助Java GUI开发
Author: nex3z
2014-05-09
WindowBuilder的前身是Instantiations开发的SWT Designer,2010年8月初Google收购了Instantiations,之后重新发布了Instantiations的开发工具,并且对所有开发人员免费,其中就包括用于Java图形界面设计的WindowBuilder。
WindowBuilder的下载地址为http://www.eclipse.org/windowbuilder/download.php。安装完成后,即可在File->New->Other…中看到WindowBuilder,如图1所示。

图1
在WindowBuilder下可以直接建立工程,也可以建立单个的窗口。假设已经建立了工程,这里选择Swing Designer下的Application Window,点击Next >后,类似于新建类,在后续对话框中输入Name和Package,如图2所示。

图2
点击Finish后,即可得到HelloWorld.java。打开HelloWorld.java,可见其中已经预先生成了一些代码,是一个空白的窗体。点击代码窗口左下角新出现“Design“标签,可以使用WindowBuilder Editor可视化地查看窗体(也可以在HelloWorld.java上点击右键,选择Open With->WindowBuilder Editor),如图3所示。

图3
WindowBuilder Eidtor的界面类似于VS等工具,能够可视化地对界面进行设计。点击Layouts下的Absolute layout,再点击窗体,使用绝对定位;点击Components下的JTextField,再点击窗体,添加一个文本框,修改其Variable属性为”txtName“;点击Components下的JButton,再点击窗体,添加一个按钮,修改其Variable属性为btnSubmit,修改其text属性为”Submit“;点击Components下的JLabel,再点击窗体,添加一个标签,修改其Variable属性为lblName,修改其text属性为”Name:“;同样方法再添加一个JLabel,修改其Variable属性为lblMessage,修改其text属性为”Please enter your name.“;调整界面尺寸,最终得到的界面如图4所示。

图4
这时点击左下角的”Source“标签回到代码编辑器,可以看到WindowBuilder生成的代码如下:
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.JButton;
public class HelloWorld {
private JTextField txtName;
* Launch the application.
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
HelloWorld window = new HelloWorld();
window.frame.setVisible(true);
* Create the application.
* Initialize the contents of the frame.
private void initialize() {
frame.setBounds(100, 100, 196, 169);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
txtName = new JTextField();
txtName.setBounds(57, 18, 93, 21);
frame.getContentPane().add(txtName);
JButton btnSubmit = new JButton("Submit");
btnSubmit.setBounds(57, 46, 93, 23);
frame.getContentPane().add(btnSubmit);
JLabel lblName = new JLabel("Name:");
lblName.setBounds(20, 21, 54, 15);
frame.getContentPane().add(lblName);
JLabel lblMessage = new JLabel("Please enter your name.");
lblMessage.setBounds(20, 79, 151, 15);
frame.getContentPane().add(lblMessage);
package text;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.JButton;
public class HelloWorld {
private JFrame frame;
private JTextField txtName;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
HelloWorld window = new HelloWorld();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public HelloWorld() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 196, 169);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
txtName = new JTextField();
txtName.setBounds(57, 18, 93, 21);
frame.getContentPane().add(txtName);
txtName.setColumns(10);
JButton btnSubmit = new JButton("Submit");
btnSubmit.setBounds(57, 46, 93, 23);
frame.getContentPane().add(btnSubmit);
JLabel lblName = new JLabel("Name:");
lblName.setBounds(20, 21, 54, 15);
frame.getContentPane().add(lblName);
JLabel lblMessage = new JLabel("Please enter your name.");
lblMessage.setBounds(20, 79, 151, 15);
frame.getContentPane().add(lblMessage);
}
}
package text;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.JButton;
public class HelloWorld {
private JFrame frame;
private JTextField txtName;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
HelloWorld window = new HelloWorld();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public HelloWorld() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 196, 169);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
txtName = new JTextField();
txtName.setBounds(57, 18, 93, 21);
frame.getContentPane().add(txtName);
txtName.setColumns(10);
JButton btnSubmit = new JButton("Submit");
btnSubmit.setBounds(57, 46, 93, 23);
frame.getContentPane().add(btnSubmit);
JLabel lblName = new JLabel("Name:");
lblName.setBounds(20, 21, 54, 15);
frame.getContentPane().add(lblName);
JLabel lblMessage = new JLabel("Please enter your name.");
lblMessage.setBounds(20, 79, 151, 15);
frame.getContentPane().add(lblMessage);
}
}
如果在点击”Source“标签前选中了某个组件,则点击”Source“回到代码编辑器后,光标则会自动定位到对应的组件。
再点击”Design“回到WindowBuilder Editor,双击Submit按钮,同大多数GUI开发工具类似,WindowBuilder认为此时要编写事件处理代码,界面自动切换到代码编辑器,且WindowBuilder已经在initialize() 中完成了监听器的定义和注册:
btnSubmit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
btnSubmit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
}
});
btnSubmit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
}
});
WindowBuilder使用匿名内部类的形式实现事件处理器。修改initialize() 加入事件处理:
private void initialize() {
frame.setBounds(100, 100, 196, 169);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
txtName = new JTextField();
txtName.setBounds(57, 18, 93, 21);
frame.getContentPane().add(txtName);
final JLabel lblMessage = new JLabel("Please enter your name.");
lblMessage.setBounds(20, 79, 151, 15);
frame.getContentPane().add(lblMessage);
JButton btnSubmit = new JButton("Submit");
btnSubmit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
lblMessage.setText("Hello " + txtName.getText() + "!");
btnSubmit.setBounds(57, 46, 93, 23);
frame.getContentPane().add(btnSubmit);
JLabel lblName = new JLabel("Name:");
lblName.setBounds(20, 21, 54, 15);
frame.getContentPane().add(lblName);
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 196, 169);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
txtName = new JTextField();
txtName.setBounds(57, 18, 93, 21);
frame.getContentPane().add(txtName);
txtName.setColumns(10);
final JLabel lblMessage = new JLabel("Please enter your name.");
lblMessage.setBounds(20, 79, 151, 15);
frame.getContentPane().add(lblMessage);
JButton btnSubmit = new JButton("Submit");
btnSubmit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
lblMessage.setText("Hello " + txtName.getText() + "!");
}
});
btnSubmit.setBounds(57, 46, 93, 23);
frame.getContentPane().add(btnSubmit);
JLabel lblName = new JLabel("Name:");
lblName.setBounds(20, 21, 54, 15);
frame.getContentPane().add(lblName);
}
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 196, 169);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
txtName = new JTextField();
txtName.setBounds(57, 18, 93, 21);
frame.getContentPane().add(txtName);
txtName.setColumns(10);
final JLabel lblMessage = new JLabel("Please enter your name.");
lblMessage.setBounds(20, 79, 151, 15);
frame.getContentPane().add(lblMessage);
JButton btnSubmit = new JButton("Submit");
btnSubmit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
lblMessage.setText("Hello " + txtName.getText() + "!");
}
});
btnSubmit.setBounds(57, 46, 93, 23);
frame.getContentPane().add(btnSubmit);
JLabel lblName = new JLabel("Name:");
lblName.setBounds(20, 21, 54, 15);
frame.getContentPane().add(lblName);
}
运行结果如图5所示。

图5
WindowBuilder能够可视化地开发界面,并自动生成大部分代码,可以极大地方便JAVA GUI的设计和开发,但WindowBuilder完成的代码毕竟为机器自动生成,对于复杂的界面和事件处理,仍需要手动对代码进行整理。多数情况下,对WindowBuilder生成的代码进行移动后,WindowBuilder Editor仍能可视化地显示界面。
在使用WindowBuilder的过程中,直接在Source视图修改了代码后,切换回Design视图时可能会出现报错的问题,此问题在Kepler版本Eclipse中尤为常见,关闭Eclipse再打开就可以正常工作了。