У меня возникла проблема со скрытыми компонентами, которые не располагаются должным образом при работе с несколькими кадрами.
Короче говоря, я не могу распоряжаться модальным диалогом, родитель которого является скрытым фреймом.
Например:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
public class MultipleFrameTest {
public static void main(String[] args) {
TestFrame test = new TestFrame();
FrameTester tester = new FrameTester(test);
tester.setVisible(true);
}
private static class TestFrame extends JFrame {
JDialog dialog;
java.util.Timer timer;
public TestFrame() {
super("Test Frame");
this.dialog = null;
this.timer = new java.util.Timer("Frame Timer");
fillFrame();
pack();
}
private void fillFrame() {
JButton dialogButton = new JButton("Launch Model Dialog");
dialogButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
JOptionPane pane = new JOptionPane("Wait for 2 seconds",
JOptionPane.QUESTION_MESSAGE,
JOptionPane.OK_CANCEL_OPTION);
dialog = pane.createDialog(TestFrame.this, "Question");
timer.schedule(new TimerTask() {
public void run() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
TestFrame.this.setVisible(false);
if (dialog != null) {
dialog.setVisible(false);
dialog.dispose();
dialog = null;
}
}
});
}
}, 2 * 1000);
dialog.setVisible(true);
}
});
JPanel panel = new JPanel();
panel.add(dialogButton);
add(panel);
}
}
private static class FrameTester extends JFrame {
JFrame frame;
public FrameTester(JFrame frame) {
super("Frame Tester");
this.frame = frame;
fillFrame();
pack();
}
private void fillFrame() {
JButton toggleButton = new JButton("Toggle Frame Visibility");
toggleButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
frame.setVisible(!frame.isVisible());
}
});
JPanel panel = new JPanel();
panel.add(toggleButton);
add(panel);
}
}
}
Чтобы запустить этот пример:
TestFrame
.JOptionPane
.TimerTask
спрятал TestFrame
и TestFrame
dispose()
JOptionPane
.TestFrame
станет видимым, и JOptionPane
будет подключен. Я знаю, что я могу это исправить, TestFrame
JOptionPane
перед тем, как скрыть TestFrame
:
- TestFrame.this.setVisible(false);
if (dialog != null) {
dialog.setVisible(false);
dialog.dispose();
dialog = null;
}
+ TestFrame.this.setVisible(false);
Кто-нибудь знает, почему это происходит? Я ожидал, что модальный диалог исчезнет, даже если он будет скрыт, когда он будет удален.
Хотя вы действительно должны рассмотреть комментарий trashgod о использовании нескольких JFrames, хорошей/плохой практике? , вот объяснение, почему вы видите это поведение.
Это происходит из-за того, что перед диалоговым окном скрывается окно владельца. Когда вы делаете такую вещь, принадлежащий диалогу будет помечен как showWithParent
и следующий вызов setVisible(true)
в кадре автоматически вызовет отображение соответствующего диалога из-за этого флага. Единственный способ избежать этого, как вы сказали в своем вопросе, - сначала скрыть принадлежащий ему диалог, а затем скрыть окно владельца.
Вот выдержка метода Window.hide()
:
synchronized(ownedWindowList) {
for (int i = 0; i < ownedWindowList.size(); i++) {
Window child = ownedWindowList.elementAt(i).get();
if ((child != null) && child.visible) {
child.hide();
child.showWithParent = true; // See here the flag set to true
}
}
}
и здесь соответствующий экстракт метода Window.show()
:
for (int i = 0; i < ownedWindowList.size(); i++) {
Window child = ownedWindowList.elementAt(i).get();
if ((child != null) && child.showWithParent) { // Here theh flag is checked
child.show();
child.showWithParent = false; // flag is then reset
} // endif
}
Btw, вместо использования этой сложной структуры таймера /TimerTask/invokeLater вы можете просто использовать javax.swing.Timer
(с setRepeats(false)
). Таймер Swing всегда запускается в Диспетчере событий.