Окна диалогов
Окна диалогов - это окна, которые всплывают из других окон. Их назначение состоит в решении специфических проблем без изменения деталей оригинального окна. Окна диалогов часто используются в оконной среде программ, и менее часто используются в апплетах.
Для создания диалога вы наследуете от JDialog, который является просто видом окна, как и JFrame. JDialog имеет менеджер компоновки (по умолчанию это BorderLayout) и вы добавляете слушатель событий для работы с событиями. Одно значительное отличие возникает при вызове windowClosing( ). Оно состоит в том, что вам не нужно завершать приложение. Вместо этого вы освобождаете ресурсы, используемые окном диалога, вызывая dispose( ). Вот простой пример:
//: c13:Dialogs.java
// Создание и использование диалогов.
// <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(); // Закрытие диалога.
} }); cp.add(ok); setSize(150,125); } }
public class Dialogs extends JApplet { JButton b1 = new JButton("Dialog Box"); 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( ).
Вы увидите, что ко всему, что всплывает из апплета, включая диалоги, нет доверия. То есть, вы получите всплывающее окно предупреждения. Это происходит потому, что, теоретически, есть возможность одурачить пользователя и заставить его думать, что он имеет дело с обычным местным приложением и дать ему напечатать номер его кредитной карточки, который будет передан через Web. Апплет всегда присоединяется в Web странице и его видно внутри вашего Web броузера, а диалог не присоединен, поэтому, теоретически, это становится возможным. В результате, не часто можно увидеть апплеты, использующие окна диалога.
Следующий пример сложнее; окно диалога сделано в виде решетки (используется GridLayout) кнопок специального рода, которые определены здесь, как класс ToeButton. Эти кнопки рисуют рамку вокруг себя и, в зависимости от состояния, остаются пустыми, рисуют “x” или “o” в середине. Изначально они пустые, а затем, в зависимости от того, кто включен, меняются на “x” или “o”. Однако также есть обратная и прямая связь между “x” и “o”, когда вы нажимаете кнопку. (Здесь воссоздается концепция tic-tac-toe, только немного более надоедливая, чем существующая.) Кроме того, диалог может быть установлен на любое число колонок и строк, путем изменения чисел в главном окне приложения.
//: c13:TicTacToe.java
// Демонстрация диалогов
// и создание ваших собственных компонент.
// <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 { JTextField rows = new JTextField("3"), cols = new JTextField("3"); static final int BLANK = 0, XX = 1, OO = 2; class ToeDialog extends JDialog { int turn = XX; // Начинается с включения x
// w = число ячеек в ширину
// h = число ячеек в высоту
public ToeDialog(int w, int h) { setTitle("The game itself"); Container cp = getContentPane(); cp.setLayout(new GridLayout(w, h)); for(int i = 0; i < w * h; i++) cp.add(new ToeButton()); setSize(w * 50, h * 50); // JDK 1.3 закрытие диалога:
//#setDefaultCloseOperation(
//# DISPOSE_ON_CLOSE);
// JDK 1.2 закрытие диалога:
addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e){ dispose(); } }); } class ToeButton extends JPanel { int state = BLANK; public ToeButton() { addMouseListener(new ML()); } public void paintComponent(Graphics g) { super.paintComponent(g); int x1 = 0; int y1 = 0; int x2 = getSize().width - 1; int y2 = getSize().height - 1; g.drawRect(x1, y1, x2, y2); x1 = x2/4; y1 = y2/4; int wide = x2/2; int 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”, то знак меняется. Вы можете видеть в расчетах последовательное использование тернарного оператора if-else, описанного в Главе 3. После смены состояния происходит перерисовка ToeButton.
Конструктор ToeDialog достаточно прост: он добавляет в GridLayout столько кнопок, сколько вы запросили, затем изменяет их размер до 50 пикселей на сторону для каждой кнопки.
TicTacToe устанавливает все приложение, создавая JTextField (для ввода числа строк и колонок кнопок в сетке) и кнопку “go” с присоединенным ActionListener. Когда нажимается кнопка, извлекаются данные из JTextField, и, так как они имеют форму String, они переводятся в int, используя статический метод Integer.parseInt( ).