qiyadeng

专注于Java示例及教程
posts - 84, comments - 152, trackbacks - 0, articles - 34

使用Swing设计向导

Posted on 2008-07-26 16:46 qiyadeng 阅读(1899) 评论(2)  编辑  收藏

向导在今天的桌面应用中非常常用。向导应该是个什么样子呢?相信你应该很清楚,因为你使用过很多的向导。也许你使用过一些安装程序向导或是一些程序的配置向导。这篇文章,我们会创建一个简单的向导框架。

一个向导包括很多Panel,每个Panel里面包含用户的配置组件或是文本域或是选择框等。用户点击”Next”或是”Back”按钮,在各个Panel之间切换,输入需要的信息。注意的是,当最后一个Panel是”Next”按钮要变成”Finish”按钮,并且再次按下的时候向导关闭。在向导关闭的时,发起向导的类要得到向导Panel中所有的数据。在任何情况下,用户可以点击”Cancel”按钮关闭向导并丢弃前面所填的所有数据。

看上去很简单是吗?对的,但是有些设计细节我们需要考虑。

第一,向导中的每个Panel不是都需要访问的,换句话说,如果向导包含1到5个Panel,点击”Next”按钮可以从第一个Panel依次到第五个Panel,但是有时候可能由于用户的选项直接从第一个Panel跳到第五个Panel. 而且还有的情况是,假设向导中需要连接到远程服务器或是远程数据库,如果连接不上的,那么就不能到达下一个Panel。这样向导中的Panel就像是树形,你从树的根开始,通过不同的分支到达叶子节点,这时”Next”按钮变成”Finish”按钮。

第二,有些时候Next按钮和Back按钮需要禁用。比如,第一个Panel出现的时候,back按钮应该禁用,因为没有上一个Panel。另外,当有些值必须输入的时候,没有输入的情况下Panel中的Next按钮应该为禁用。

第三,输入的数据需要一直保持到用户完成向导或是取消。因为当用户点击Back按钮会到上一个Panel时,上一个Panel填写的数据应该能够保持,并且再次使用Next按钮时,本Panel中的数据也应该保持。

有了这些设计细节,我们可以考虑设计自己的向导了。我们先规划下我们将要完成的一些类。

Wizard-这个类包含模型(model)和控制器(controller),其主要是一个对话框(JDialog),并且包含有Next,Back和Cancel按钮。还有一个使用CardLayout布局管理的大组件,可以把各个Panel显示在上面。想下图的样子:

clip_image002

Java.awt.Componet的子类,这个类一般是继承了java.awt.Componet,通常是一个javax.swing.JPanel.这个类是用于显示在wizard类中的大组件位置。下图是其中一个Panel。

clip_image004

WizardPanelDescriptor-这第三个类用于关联wizard和panel。这个需要类用户继承,并用于标识Panel.这个类指定了访问下一个和前一个Panel的规则,并且在Panel的显示前,现实中,和显示后执行相应的动作。

Wizard

首先我们需要创建一个用于显示向导对话框本身,它包含有三个按钮Back,Next,Cancel.一般这些按钮是按照从左到右的顺序分布的,另外Cancel按钮要离其他的两个按钮远一点,这样防止用户不小心点击到Cancel按钮。接下来,就用需要一个布局,可以在同一个区域显示各个Panel,在AWT中有CardLayout布局。

在这个设计中,我们使用一个简单的方法来检测我们的数据。下面我们看看Wizard类:

Public Class Wizard{

private WizardModel wizardModel;

private WizardController wizardController;

private JDialog wizardDialog;

private JPanel cardPanel;

private CardLayout cardLayout;

private JButton backButton;

private JButton nextButton;

private JButton cancelButton;

private MainFrame mainFrame;

private int returnCode;

public Wizard(MainFrame owner) {

this.mainFrame = owner;

wizardModel = new WizardModel();

wizardDialog = new JDialog(owner);

Point np = owner.getLocation();

wizardDialog.setLocation(np);

initComponents();

}

}

注意到initComponents()方法,这个方法是用于布置界面中的组件和按钮的,并且把按钮事件关联到控制器中。

private void initComponents() {

JPanel buttonPanel = new JPanel();

Box buttonBox = new Box(BoxLayout.X_AXIS);

cardPanel = new JPanel();

cardPanel.setBorder(new EmptyBorder(new Insets(5, 10, 5, 10)));

cardLayout = new CardLayout();

cardPanel.setLayout(cardLayout);

backButton = new JButton();

nextButton = new JButton();

cancelButton = new JButton();

backButton.setActionCommand(BACK_BUTTON_ACTION_COMMAND);

nextButton.setActionCommand(NEXT_BUTTON_ACTION_COMMAND);

cancelButton.setActionCommand(CANCEL_BUTTON_ACTION_COMMAND);

buttonPanel.setLayout(new BorderLayout());

buttonPanel.add(separator, BorderLayout.NORTH);

buttonBox.setBorder(new EmptyBorder(new Insets(5, 10, 5, 10)));

buttonBox.add(backButton);

buttonBox.add(Box.createHorizontalStrut(10));

buttonBox.add(nextButton);

buttonBox.add(Box.createHorizontalStrut(30));

buttonBox.add(cancelButton);

buttonPanel.add(buttonBox, java.awt.BorderLayout.EAST);

wizardDialog.getContentPane().add(buttonPanel, java.awt.BorderLayout.SOUTH);

wizardDialog.getContentPane().add(cardPanel, java.awt.BorderLayout.CENTER);

}

接下来,我们要把Componet Panel注册到Wizard中。Wzard中使用registerWizardPanel()方法。我们知道CardLayout布局中包含有next(),previous()这样的方法来回翻动Panel,然而我们需要的是树形结构,而不是线性的结构,因此我们需要使用标识符来标识各个Panel对象。

public void registerWizardPanel(Object id, WizardPanelDescriptor panel) {

cardPanel.add(panel.getPanelComponent(), id);

wizardMdel.registerPanel(id, panel);

}

最后wizard中是用setCurrentPanel(Object id)来设置,Wizard初始化时显示的第一个Panel。剩下的就是一些事件处理,比较简单。Wizard中大量的使用Wizard来保存数据,并使用WizardController来处理对话框本身的事件。

WizardPanelDescriptor

注册到Wizard的每个方法都需要继承WizardPanelDescriptor类,这个类包含一些方法可以把组件集成到Wizard向导中。以下的四个方法:是访问组件和组件对象标识符的方法。

public final void setPanelComponent(Component panel) {

targetPanel = panel;

}

public final Component getPanelComponent() {

return targetPanel;

}

public final Object getPanelDescriptorIdentifier() {

return panelIdentifier;

}

public final void setPanelDescriptorIdentifier(Object id) {

panelIdentifier = id;

}

下面是比较重要的一部分,就是每个继承类都需要改写的一些方法。包括控制Next,Back之后显示的Panel。在每次Panel初始化的时候都会执行Next这个方法,当Next和Back方法中返回的是null之的时候Next和Back按钮被禁用。因此,Next方法不能用于数据的校验,需要有另外的方法,在这里使用了一个Validator方法,当然如果数据需要校验,也需要在WizardPanelDescriptor子类中进行覆盖。具体如下:

public Object getNextPanelDescriptor() {

return null;

}

public Object getBackPanelDescriptor() {

return null;

}

public boolean validator(){

return true;

}

另外提供三个方法,用于控制Panel显示前,显示中和显示后的事件。

public void aboutToDisplayPanel() {

}

public void displayingPanel() {

}

public void aboutToHidePanel() {

}

WizardPanelDescriptor

clip_image007

最后,用上图来表示Wizard类和其他几个类之间的关系图,并展示了两个实例。

Feedback

# re: 使用Swing设计向导  回复  更多评论   

2008-10-17 12:00 by hb148
Swing Wizard Framework
https://wizard-framework.dev.java.net/

# re: 使用Swing设计向导  回复  更多评论   

2013-09-11 10:24 by 洛玻
有该项目的详细代码嘛?你能发一份给我嘛?谢谢

只有注册用户登录后才能发表评论。


网站导航: