首先声明,偶是菜鸟!所以高手看这篇文章前请平心静气,看完后请勿破口大骂,谢谢!欢迎友好的评论!
最近对制做窗体产生极大的兴趣(唉,又一个不务正业者)。整天在那边琢磨这个窗体是怎么做的,那个窗体是怎么设计的,恨不得把电脑里装的程序一个个大卸八块仔细研究研究(走火入魔了,-_-|||)。今天琢磨了一下向导的制做方法,弄出来大家讨论讨论……
一个向导运行的过程中,可能会加载很多JPanel,如果采用临时加载的办法,运行时就会比较慢。所以我采用在向导启动时全部加载,这样启动的时候会较慢,但是运行时就快了。观察发现,和用PS制做图像的图层相反,java在加载组件的时候,先加载的组件将覆盖后面的组件。这样我们就可以把所有的JPanel加载在同一个位置,要显示下一个JPanel的时候只要把当前的setVisible(false);再repaint();就行了。现在问题出来了,有些组件会透过前面的JPanel显示出来,比如JTextField。怎么办呢?把不需要显示的JPanel全部setVisible(false);整个世界清静了……
现在我们解决了一个显示的问题。Next problem is NEXT.向导不是光用来看的。首先我们要捕获用户的输入,然后判断用户的输入是否合法,无效的输入要产生错误提示,有效的输入才能继续。当然我们不能在GuideFrame类中做这些事情,否则就不能重用了。所以我们要声明一个Interface:
package nicholas.swing;
public interface Checkable {
public boolean check();
public String getErrorMessage();
}
再声明一个Abstract class:
package nicholas.swing;
import javax.swing.*;
public abstract class CheckPanel extends JPanel implements Checkable {
public CheckPanel() {
this.setVisible(false);
this.setBorder(BorderFactory.createEtchedBorder());
}
public abstract String getTitle();
public abstract String getDetail();
}
现在我们可以使用CheckPanel的子类来实现所有的输入检查操作,而GuideFrame只要获得检查的结果并决定是否调用下一个CheckPanel就可以了。下面是GuideFrame的代码:
package nicholas.swing;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class GuideFrame extends JFrame implements ActionListener {
private CheckPanel panel[];
private JButton nextButton;
private JButton prevButton;
private JButton exitButton;
private JLabel titleLabel;
private JLabel detailLabel;
private JLabel imageLabel;
private int current;
public GuideFrame() {
super();
current = 0;
getContentPane().setLayout(null);
setupUI();
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
setResizable(false);
setSize(500,360);
Dimension screen = getToolkit().getScreenSize();
setLocation((screen.width-getSize().width)/2, (screen.height-getSize().height)/2);
show();
}
public void setPanel(CheckPanel p[]) {
panel = p;
for(int i=0;i<panel.length;i++) {
panel[i].setBounds(-2,53,504,235);
getContentPane().add(panel[i]);
}
panel[0].setVisible(true);
}
private void setupUI() {
titleLabel = new JLabel("标题");
titleLabel.setBounds(10,5,200,20);
detailLabel = new JLabel("详细");
detailLabel.setBounds(20,20,300,20);
//enable this sentence will greatly slow down the speed.
// detailLabel.setFont(new Font("宋体",Font.PLAIN,12));
imageLabel = new JLabel();
imageLabel.setBounds(445,7,40,40);
imageLabel.setBorder(BorderFactory.createEtchedBorder());
JPanel panel = new JPanel(null);
panel.setBounds(0,0,500,53);
panel.setBackground(Color.white);
panel.add(titleLabel);
panel.add(detailLabel);
panel.add(imageLabel);
getContentPane().add(panel);
prevButton = new JButton("上一步");
prevButton.setBounds(245,298,75,21);
prevButton.addActionListener(this);
prevButton.setVisible(false);
nextButton = new JButton("下一步");
nextButton.setBounds(325,298,75,21);
nextButton.addActionListener(this);
exitButton = new JButton("取消");
exitButton.setBounds(413,298,65,21);
exitButton.addActionListener(this);
getContentPane().add(prevButton);
getContentPane().add(nextButton);
getContentPane().add(exitButton);
}
private void quit() {
}
public void actionPerformed(ActionEvent ae) {
if(ae.getSource()==exitButton) {
int result = JOptionPane.showConfirmDialog(this,"您是否确认要退出本向导?\n所有信息将丢失.",
"退出",JOptionPane.YES_NO_OPTION,JOptionPane.INFORMATION_MESSAGE);
if(result==JOptionPane.YES_OPTION) {
System.exit(0);
}
} else if(ae.getSource()==nextButton) {
if(panel[current].check()) {
//can do next job
panel[current].setVisible(false);
current++;
if(current==1) {
prevButton.setVisible(true);
}
if(current==(panel.length-1)) {
prevButton.setVisible(false);
nextButton.setText("完成");
} else if(current==panel.length) {
quit();
return;
}
panel[current].setVisible(true);
repaint();
} else {
//cannot continue
JOptionPane.showMessageDialog(this,panel[current].getErrorMessage(),
"警告",JOptionPane.ERROR_MESSAGE);
return;
}
} else {
panel[current].setVisible(false);
current--;
panel[current].setVisible(true);
if(current==0) {
prevButton.setVisible(false);
}
repaint();
}
}
}
其中titleLabel、detailLabel、imageLabel可以放在CheckPanel中,但是个人觉得放在GuideFrame里比较好,只是CheckPanel跳转时要同时给前两个JLabel赋值比较麻烦(代码没给出,偶懒……)。另外还没琢磨出来license panel要怎么弄……
如果您有任何意见或建议,请不吝指出,谢谢!
Nicholas Lin @ Jan 8,2005