对话框是从视窗弹出的另一个窗口。它的目的是处理一些具体问题,同时又不会使这些具
体细节与原先窗口的内容混在一起。对话框在视窗编程环境下被大量使用,不过在applet
中比较少见。
如果要编写一个对话框,就需要从 JDialog 继承,它只不过是另一种类型的 Window,与
JFrame 类似。JDialog 具有一个布局管理器(缺省情况下为 BorderLayout),并且你要
添加事件监听器来处理事件。它与别的 Window 相比,有一个明显不同的地方,就是当你
关闭对话框窗口的时候,并不希望关闭整个应用程序。这时候的做法是通过调用 dispose( )
方法来释放对话框窗口所占用的资源。下面是个简单的例子:
//: c14:Dialogs.java
// Creating and using Dialog Boxes.
// <applet code=Dialogs width=125 height=75></applet>
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import com.bruceeckel.swing.*;
class MyDialog extends JDialog {
public MyDialog(JFrame parent) {
super(parent, "My dialog", true);
Container cp = getContentPane();
cp.setLayout(new FlowLayout());
cp.add(new JLabel("Here is my dialog"));
JButton ok = new JButton("OK");
ok.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
dispose(); // Closes the dialog
}
});
cp.add(ok);
setSize(150,125);
}
}
public class Dialogs extends JApplet {
private JButton b1 = new JButton("Dialog Box");
private MyDialog dlg = new MyDialog(null);
public void init() {
b1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
dlg.show();
}
});
getContentPane().add(b1);
}
public static void main(String[] args) {
Console.run(new Dialogs(), 125, 75);
}
} ///:~
创建JDialog以后,要显示和激活它就必须调用show( )方法。而要关闭对话框则必须调用
dispose( )。
你将发现,任何从applet弹出的窗体,包括对话框在内,都是“不受信任”的。也就是说,
你将从被弹出的窗体中得到警告信息。这是因为至少从理论上讲,弹出的窗体有可能欺骗
用户,使他们认为自己在操作一个常规的本地程序,比如让用户输入他们的信用卡号码,
从而使这个号码被散布到网络上。Applet总是嵌入在某个网页内的,并且在浏览器中是可
视的,而applet又可以弹出对话框,所以从理论上讲,这是有可能的。因此,使用对话框
的applet并不常见。
下面的例子更加复杂;对话框由一个网格构成(使用 GridLayout),并且添加了一种特殊
按钮,它由 ToeButton 类定义。按钮将先在自己周围画一个边框,然后根据状态的不同,
在中央画“空白”,“x”或者“o”。开始时的按钮状态为“空白”,然后根据每一轮单
击,变成“x”或者“o”。而且,当你在非“空白”的按钮上单击的时候,它将在“x”和
“o”之间翻转(这采用了三值翻转(tic-tac-toe)的概念,只是为了使程序比目前更复杂)。
此外,通过改变在主应用视窗中的数字,可以为对话框设置任意的行数和列数。
//: c14:TicTacToe.java
// Dialog boxes and creating your own components.
// <applet code=TicTacToe width=200 height=100></applet>
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import com.bruceeckel.swing.*;
public class TicTacToe extends JApplet {
private JTextField
rows = new JTextField("3"),
cols = new JTextField("3");
private static final int BLANK = 0, XX = 1, OO = 2;
class ToeDialog extends JDialog {
private int turn = XX; // Start with x's turn
ToeDialog(int cellsWide, int cellsHigh) {
setTitle("The game itself");
Container cp = getContentPane();
cp.setLayout(new GridLayout(cellsWide, cellsHigh));
for(int i = 0; i < cellsWide * cellsHigh; i++)
cp.add(new ToeButton());
setSize(cellsWide * 50, cellsHigh * 50);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
}
class ToeButton extends JPanel {
private int state = BLANK;
public ToeButton() { addMouseListener(new ML()); }
public void paintComponent(Graphics g) {
super.paintComponent(g);
int
x1 = 0, y1 = 0,
x2 = getSize().width - 1,
y2 = getSize().height - 1;
g.drawRect(x1, y1, x2, y2);
x1 = x2/4;
y1 = y2/4;
int wide = x2/2, high = y2/2;
if(state == XX) {
g.drawLine(x1, y1, x1 + wide, y1 + high);
g.drawLine(x1, y1 + high, x1 + wide, y1);
}
if(state == OO)
g.drawOval(x1, y1, x1 + wide/2, y1 + high/2);
}
class ML extends MouseAdapter {
public void mousePressed(MouseEvent e) {
if(state == BLANK) {
state = turn;
turn = (turn == XX ? OO : XX);
}
else
state = (state == XX ? OO : XX);
repaint();
}
}
}
}
class BL implements ActionListener {
public void actionPerformed(ActionEvent e) {
JDialog d = new ToeDialog(
Integer.parseInt(rows.getText()),
Integer.parseInt(cols.getText()));
d.setVisible(true);
}
}
public void init() {
JPanel p = new JPanel();
p.setLayout(new GridLayout(2,2));
p.add(new JLabel("Rows", JLabel.CENTER));
p.add(rows);
p.add(new JLabel("Columns", JLabel.CENTER));
p.add(cols);
Container cp = getContentPane();
cp.add(p, BorderLayout.NORTH);
JButton b = new JButton("go");
b.addActionListener(new BL());
cp.add(b, BorderLayout.SOUTH);
}
public static void main(String[] args) {
Console.run(new TicTacToe(), 200, 100);
}
} ///:~
因为static关键字只能处于类的外层,所以内部类不能包含静态的数据或者嵌套类。
paintComponent( )方法先在面板周围绘制正方形,然后在中间画“x”或“o”。这里充
满了乏味的计算,但是却很直接明了。
MouseListener被用来处理鼠标单击:首先,它检查面板上是否为空白,如果不是空白,
就向父窗体查询现在是哪一轮,这样就得到了ToeButton的状态。通过内部类机制,
ToeButton可以操作其外部类,更新当前的轮次;如果按钮已经显示为“x”或“o”,那
么就翻转它。在这个计算中,你可以看到第 3 章学习的if-else三元运算符的习惯用法。在
状态改变之后,ToeButton将被重绘。
ToeDialog的构造器非常简单;它向网格中添加你所要求数目的按钮,然后调整窗体大小,
使得每个按钮的长和宽均为 50 个像素。
TicTacToe通过创建两个TextField(用来输入按钮网格的行数和列数)和带有
ActionListener的“go”按钮,完成整个程序的设置工作。当按钮被按下时,将获取
JTextField里面的数据,因为它们是字符串,所以使用静态的Integer.parseInt( )方法把
体细节与原先窗口的内容混在一起。对话框在视窗编程环境下被大量使用,不过在applet
中比较少见。
如果要编写一个对话框,就需要从 JDialog 继承,它只不过是另一种类型的 Window,与
JFrame 类似。JDialog 具有一个布局管理器(缺省情况下为 BorderLayout),并且你要
添加事件监听器来处理事件。它与别的 Window 相比,有一个明显不同的地方,就是当你
关闭对话框窗口的时候,并不希望关闭整个应用程序。这时候的做法是通过调用 dispose( )
方法来释放对话框窗口所占用的资源。下面是个简单的例子:
//: c14:Dialogs.java
// Creating and using Dialog Boxes.
// <applet code=Dialogs width=125 height=75></applet>
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import com.bruceeckel.swing.*;
class MyDialog extends JDialog {
public MyDialog(JFrame parent) {
super(parent, "My dialog", true);
Container cp = getContentPane();
cp.setLayout(new FlowLayout());
cp.add(new JLabel("Here is my dialog"));
JButton ok = new JButton("OK");
ok.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
dispose(); // Closes the dialog
}
});
cp.add(ok);
setSize(150,125);
}
}
public class Dialogs extends JApplet {
private JButton b1 = new JButton("Dialog Box");
private MyDialog dlg = new MyDialog(null);
public void init() {
b1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
dlg.show();
}
});
getContentPane().add(b1);
}
public static void main(String[] args) {
Console.run(new Dialogs(), 125, 75);
}
} ///:~
创建JDialog以后,要显示和激活它就必须调用show( )方法。而要关闭对话框则必须调用
dispose( )。
你将发现,任何从applet弹出的窗体,包括对话框在内,都是“不受信任”的。也就是说,
你将从被弹出的窗体中得到警告信息。这是因为至少从理论上讲,弹出的窗体有可能欺骗
用户,使他们认为自己在操作一个常规的本地程序,比如让用户输入他们的信用卡号码,
从而使这个号码被散布到网络上。Applet总是嵌入在某个网页内的,并且在浏览器中是可
视的,而applet又可以弹出对话框,所以从理论上讲,这是有可能的。因此,使用对话框
的applet并不常见。
下面的例子更加复杂;对话框由一个网格构成(使用 GridLayout),并且添加了一种特殊
按钮,它由 ToeButton 类定义。按钮将先在自己周围画一个边框,然后根据状态的不同,
在中央画“空白”,“x”或者“o”。开始时的按钮状态为“空白”,然后根据每一轮单
击,变成“x”或者“o”。而且,当你在非“空白”的按钮上单击的时候,它将在“x”和
“o”之间翻转(这采用了三值翻转(tic-tac-toe)的概念,只是为了使程序比目前更复杂)。
此外,通过改变在主应用视窗中的数字,可以为对话框设置任意的行数和列数。
//: c14:TicTacToe.java
// Dialog boxes and creating your own components.
// <applet code=TicTacToe width=200 height=100></applet>
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import com.bruceeckel.swing.*;
public class TicTacToe extends JApplet {
private JTextField
rows = new JTextField("3"),
cols = new JTextField("3");
private static final int BLANK = 0, XX = 1, OO = 2;
class ToeDialog extends JDialog {
private int turn = XX; // Start with x's turn
ToeDialog(int cellsWide, int cellsHigh) {
setTitle("The game itself");
Container cp = getContentPane();
cp.setLayout(new GridLayout(cellsWide, cellsHigh));
for(int i = 0; i < cellsWide * cellsHigh; i++)
cp.add(new ToeButton());
setSize(cellsWide * 50, cellsHigh * 50);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
}
class ToeButton extends JPanel {
private int state = BLANK;
public ToeButton() { addMouseListener(new ML()); }
public void paintComponent(Graphics g) {
super.paintComponent(g);
int
x1 = 0, y1 = 0,
x2 = getSize().width - 1,
y2 = getSize().height - 1;
g.drawRect(x1, y1, x2, y2);
x1 = x2/4;
y1 = y2/4;
int wide = x2/2, high = y2/2;
if(state == XX) {
g.drawLine(x1, y1, x1 + wide, y1 + high);
g.drawLine(x1, y1 + high, x1 + wide, y1);
}
if(state == OO)
g.drawOval(x1, y1, x1 + wide/2, y1 + high/2);
}
class ML extends MouseAdapter {
public void mousePressed(MouseEvent e) {
if(state == BLANK) {
state = turn;
turn = (turn == XX ? OO : XX);
}
else
state = (state == XX ? OO : XX);
repaint();
}
}
}
}
class BL implements ActionListener {
public void actionPerformed(ActionEvent e) {
JDialog d = new ToeDialog(
Integer.parseInt(rows.getText()),
Integer.parseInt(cols.getText()));
d.setVisible(true);
}
}
public void init() {
JPanel p = new JPanel();
p.setLayout(new GridLayout(2,2));
p.add(new JLabel("Rows", JLabel.CENTER));
p.add(rows);
p.add(new JLabel("Columns", JLabel.CENTER));
p.add(cols);
Container cp = getContentPane();
cp.add(p, BorderLayout.NORTH);
JButton b = new JButton("go");
b.addActionListener(new BL());
cp.add(b, BorderLayout.SOUTH);
}
public static void main(String[] args) {
Console.run(new TicTacToe(), 200, 100);
}
} ///:~
因为static关键字只能处于类的外层,所以内部类不能包含静态的数据或者嵌套类。
paintComponent( )方法先在面板周围绘制正方形,然后在中间画“x”或“o”。这里充
满了乏味的计算,但是却很直接明了。
MouseListener被用来处理鼠标单击:首先,它检查面板上是否为空白,如果不是空白,
就向父窗体查询现在是哪一轮,这样就得到了ToeButton的状态。通过内部类机制,
ToeButton可以操作其外部类,更新当前的轮次;如果按钮已经显示为“x”或“o”,那
么就翻转它。在这个计算中,你可以看到第 3 章学习的if-else三元运算符的习惯用法。在
状态改变之后,ToeButton将被重绘。
ToeDialog的构造器非常简单;它向网格中添加你所要求数目的按钮,然后调整窗体大小,
使得每个按钮的长和宽均为 50 个像素。
TicTacToe通过创建两个TextField(用来输入按钮网格的行数和列数)和带有
ActionListener的“go”按钮,完成整个程序的设置工作。当按钮被按下时,将获取
JTextField里面的数据,因为它们是字符串,所以使用静态的Integer.parseInt( )方法把
它们解析成整数。