SWING モーダルダイアログを出した後に、フレームを表示すると操作ができなくなってしまう。
2006/06/22
2006/11/26
「モーダルダイアログを出した後に、フレームを表示すると操作ができなくなってしまう。」
という現象を発現させてみます。
発現手順
モーダルダイアログをフレームでサンドウィッチする状態をつくると、中にはさまれたダイアログにたいする操作ができなくなります。
ようするにプログラムの仕組みが悪いといわれればそれまですが。。。
問題を発現するためのサンプルコードです。
実行環境によっては発現しないかもしれません。ダイアログを別フレームで覆い隠してあとから表示すれば発現すると思います。
import java.awt.Rectangle;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class TestHideDailog {
public static boolean showYesNoDialog(String title, String message) {
int ret = JOptionPane.showConfirmDialog(null, message, title,
JOptionPane.YES_NO_OPTION);
if (ret == JOptionPane.YES_OPTION)
return true;
return false;
}
public static Runnable createDialogRunnable(final String title, final String message){
return new Runnable() {
public void run() {
showYesNoDialog(title, message);
}};
}
public static void main(String[] args) throws InterruptedException {
Runnable runnableFrame = new Runnable() {
public void run() {
JFrame frame = new JFrame();
frame.setBounds(new Rectangle(300, 300, 900, 500));
frame.setVisible(true);
}
};
new Thread(runnableFrame).start();
new Thread(createDialogRunnable("dialog1", "@_@!1")).start();
new Thread(createDialogRunnable("dialog2", "@_@!2")).start();
new Thread(createDialogRunnable("dialog3", "@_@!3")).start();
Thread.sleep(1000);//need wait!!
new Thread(runnableFrame).start();
}
}
下記に解決のためのサンプルコードを提示します。
解決策として、モーダルダイアログからフォーカスがはずれた場合にダイアログにフォーカスを戻すようにしてみます。
下記のコードは一部、JDKのJOptionPaneのコードを参考にしています。
import java.awt.Component;
import java.awt.HeadlessException;
import java.awt.Rectangle;
import java.awt.event.WindowEvent;
import java.awt.event.WindowFocusListener;
import javax.swing.Icon;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
public class TestHideDailog_solved {
public static boolean showYesNoDialog(String title, String message) {
int ret = showOptionDialog(null, message, title,
JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null,
null, null);
if (ret == JOptionPane.YES_OPTION)
return true;
return false;
}
public static Runnable createDialogRunnable(final String title,
final String message) {
return new Runnable() {
public void run() {
showYesNoDialog(title, message);
}
};
}
public static void main(String[] args) throws InterruptedException {
Runnable runnableFrame = new Runnable() {
public void run() {
JFrame frame = new JFrame();
frame.setBounds(new Rectangle(300, 300, 900, 500));
frame.setVisible(true);
}
};
new Thread(runnableFrame).start();
new Thread(createDialogRunnable("dialog1", "@_@!1")).start();
new Thread(createDialogRunnable("dialog2", "@_@!2")).start();
new Thread(createDialogRunnable("dialog3", "@_@!3")).start();
Thread.sleep(1000);// need wait!!
new Thread(runnableFrame).start();
}
/**
* swing(JOptionPane) java source is be used as reference.
*/
public static int showOptionDialog(Component parentComponent,
Object message, String title, int optionType, int messageType,
Icon icon, Object[] options, Object initialValue)
throws HeadlessException {
JOptionPane pane = new JOptionPane(message, messageType, optionType,
icon, options, initialValue);
pane.setInitialValue(initialValue);
pane.setComponentOrientation(((parentComponent == null) ? JOptionPane
.getRootFrame() : parentComponent).getComponentOrientation());
final JDialog dialog = pane.createDialog(parentComponent, title);
WindowFocusListener focusListener = new WindowFocusListener() {
public void windowGainedFocus(WindowEvent e) {
}
/*
* フォーカスをダイアログに変更する。
*/
public void windowLostFocus(WindowEvent e) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
dialog.requestFocus();
}
});
}
};
dialog.addWindowFocusListener(focusListener);
pane.selectInitialValue();
dialog.show();
dialog.dispose();
Object selectedValue = pane.getValue();
if (selectedValue == null)
return JOptionPane.CLOSED_OPTION;
if (options == null) {
if (selectedValue instanceof Integer)
return ((Integer) selectedValue).intValue();
return JOptionPane.CLOSED_OPTION;
}
for (int counter = 0, maxCounter = options.length; counter < maxCounter; counter++) {
if (options[counter].equals(selectedValue))
return counter;
}
return JOptionPane.CLOSED_OPTION;
}
}
別の解決策です。 JDK1.5(Tiger)を使用している場合、 Window#setAlwaysOnTop(true)を使用すると解決します。 参考: http://www.javainthebox.net/laboratory/J2SE1.5/GUI/WindowLocation/WindowLocation.html
JDK1.5にはWindow操作のためのいくつかの機能が追加されているようです。
import java.awt.Component;
import java.awt.HeadlessException;
import java.awt.Rectangle;
import javax.swing.Icon;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class TestHideDailog_solved_jdk15 {
public static boolean showYesNoDialog(String title, String message) {
int ret = showOptionDialog(null, message, title,
JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null,
null, null);
if (ret == JOptionPane.YES_OPTION)
return true;
return false;
}
public static Runnable createDialogRunnable(final String title,
final String message) {
return new Runnable() {
public void run() {
showYesNoDialog(title, message);
}
};
}
public static void main(String[] args) throws InterruptedException {
Runnable runnableFrame = new Runnable() {
public void run() {
JFrame frame = new JFrame();
frame.setBounds(new Rectangle(300, 300, 900, 500));
frame.setVisible(true);
}
};
new Thread(runnableFrame).start();
new Thread(createDialogRunnable("dialog1", "@_@!1")).start();
new Thread(createDialogRunnable("dialog2", "@_@!2")).start();
new Thread(createDialogRunnable("dialog3", "@_@!3")).start();
Thread.sleep(1000);// need wait!!
new Thread(runnableFrame).start();
}
/**
* swing(JOptionPane) java source is be used as reference.
*/
public static int showOptionDialog(Component parentComponent,
Object message, String title, int optionType, int messageType,
Icon icon, Object[] options, Object initialValue)
throws HeadlessException {
JOptionPane pane = new JOptionPane(message, messageType, optionType,
icon, options, initialValue);
pane.setInitialValue(initialValue);
pane.setComponentOrientation(((parentComponent == null) ? JOptionPane
.getRootFrame() : parentComponent).getComponentOrientation());
final JDialog dialog = pane.createDialog(parentComponent, title);
pane.selectInitialValue();
dialog.setAlwaysOnTop(true);
dialog.show();
dialog.dispose();
Object selectedValue = pane.getValue();
if (selectedValue == null)
return JOptionPane.CLOSED_OPTION;
if (options == null) {
if (selectedValue instanceof Integer)
return ((Integer) selectedValue).intValue();
return JOptionPane.CLOSED_OPTION;
}
for (int counter = 0, maxCounter = options.length; counter < maxCounter; counter++) {
if (options[counter].equals(selectedValue))
return counter;
}
return JOptionPane.CLOSED_OPTION;
}
}
という現象を発現させてみます。
発現手順
- フレームを表示します。
- モーダルダイアログを表示します。
- 別スレッドでフレームを重ねて表示します。
モーダルダイアログをフレームでサンドウィッチする状態をつくると、中にはさまれたダイアログにたいする操作ができなくなります。
ようするにプログラムの仕組みが悪いといわれればそれまですが。。。
問題を発現するためのサンプルコードです。
実行環境によっては発現しないかもしれません。ダイアログを別フレームで覆い隠してあとから表示すれば発現すると思います。
import java.awt.Rectangle;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class TestHideDailog {
public static boolean showYesNoDialog(String title, String message) {
int ret = JOptionPane.showConfirmDialog(null, message, title,
JOptionPane.YES_NO_OPTION);
if (ret == JOptionPane.YES_OPTION)
return true;
return false;
}
public static Runnable createDialogRunnable(final String title, final String message){
return new Runnable() {
public void run() {
showYesNoDialog(title, message);
}};
}
public static void main(String[] args) throws InterruptedException {
Runnable runnableFrame = new Runnable() {
public void run() {
JFrame frame = new JFrame();
frame.setBounds(new Rectangle(300, 300, 900, 500));
frame.setVisible(true);
}
};
new Thread(runnableFrame).start();
new Thread(createDialogRunnable("dialog1", "@_@!1")).start();
new Thread(createDialogRunnable("dialog2", "@_@!2")).start();
new Thread(createDialogRunnable("dialog3", "@_@!3")).start();
Thread.sleep(1000);//need wait!!
new Thread(runnableFrame).start();
}
}
下記に解決のためのサンプルコードを提示します。
解決策として、モーダルダイアログからフォーカスがはずれた場合にダイアログにフォーカスを戻すようにしてみます。
下記のコードは一部、JDKのJOptionPaneのコードを参考にしています。
import java.awt.Component;
import java.awt.HeadlessException;
import java.awt.Rectangle;
import java.awt.event.WindowEvent;
import java.awt.event.WindowFocusListener;
import javax.swing.Icon;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
public class TestHideDailog_solved {
public static boolean showYesNoDialog(String title, String message) {
int ret = showOptionDialog(null, message, title,
JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null,
null, null);
if (ret == JOptionPane.YES_OPTION)
return true;
return false;
}
public static Runnable createDialogRunnable(final String title,
final String message) {
return new Runnable() {
public void run() {
showYesNoDialog(title, message);
}
};
}
public static void main(String[] args) throws InterruptedException {
Runnable runnableFrame = new Runnable() {
public void run() {
JFrame frame = new JFrame();
frame.setBounds(new Rectangle(300, 300, 900, 500));
frame.setVisible(true);
}
};
new Thread(runnableFrame).start();
new Thread(createDialogRunnable("dialog1", "@_@!1")).start();
new Thread(createDialogRunnable("dialog2", "@_@!2")).start();
new Thread(createDialogRunnable("dialog3", "@_@!3")).start();
Thread.sleep(1000);// need wait!!
new Thread(runnableFrame).start();
}
/**
* swing(JOptionPane) java source is be used as reference.
*/
public static int showOptionDialog(Component parentComponent,
Object message, String title, int optionType, int messageType,
Icon icon, Object[] options, Object initialValue)
throws HeadlessException {
JOptionPane pane = new JOptionPane(message, messageType, optionType,
icon, options, initialValue);
pane.setInitialValue(initialValue);
pane.setComponentOrientation(((parentComponent == null) ? JOptionPane
.getRootFrame() : parentComponent).getComponentOrientation());
final JDialog dialog = pane.createDialog(parentComponent, title);
WindowFocusListener focusListener = new WindowFocusListener() {
public void windowGainedFocus(WindowEvent e) {
}
/*
* フォーカスをダイアログに変更する。
*/
public void windowLostFocus(WindowEvent e) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
dialog.requestFocus();
}
});
}
};
dialog.addWindowFocusListener(focusListener);
pane.selectInitialValue();
dialog.show();
dialog.dispose();
Object selectedValue = pane.getValue();
if (selectedValue == null)
return JOptionPane.CLOSED_OPTION;
if (options == null) {
if (selectedValue instanceof Integer)
return ((Integer) selectedValue).intValue();
return JOptionPane.CLOSED_OPTION;
}
for (int counter = 0, maxCounter = options.length; counter < maxCounter; counter++) {
if (options[counter].equals(selectedValue))
return counter;
}
return JOptionPane.CLOSED_OPTION;
}
}
別の解決策です。 JDK1.5(Tiger)を使用している場合、 Window#setAlwaysOnTop(true)を使用すると解決します。 参考: http://www.javainthebox.net/laboratory/J2SE1.5/GUI/WindowLocation/WindowLocation.html
JDK1.5にはWindow操作のためのいくつかの機能が追加されているようです。
import java.awt.Component;
import java.awt.HeadlessException;
import java.awt.Rectangle;
import javax.swing.Icon;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class TestHideDailog_solved_jdk15 {
public static boolean showYesNoDialog(String title, String message) {
int ret = showOptionDialog(null, message, title,
JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null,
null, null);
if (ret == JOptionPane.YES_OPTION)
return true;
return false;
}
public static Runnable createDialogRunnable(final String title,
final String message) {
return new Runnable() {
public void run() {
showYesNoDialog(title, message);
}
};
}
public static void main(String[] args) throws InterruptedException {
Runnable runnableFrame = new Runnable() {
public void run() {
JFrame frame = new JFrame();
frame.setBounds(new Rectangle(300, 300, 900, 500));
frame.setVisible(true);
}
};
new Thread(runnableFrame).start();
new Thread(createDialogRunnable("dialog1", "@_@!1")).start();
new Thread(createDialogRunnable("dialog2", "@_@!2")).start();
new Thread(createDialogRunnable("dialog3", "@_@!3")).start();
Thread.sleep(1000);// need wait!!
new Thread(runnableFrame).start();
}
/**
* swing(JOptionPane) java source is be used as reference.
*/
public static int showOptionDialog(Component parentComponent,
Object message, String title, int optionType, int messageType,
Icon icon, Object[] options, Object initialValue)
throws HeadlessException {
JOptionPane pane = new JOptionPane(message, messageType, optionType,
icon, options, initialValue);
pane.setInitialValue(initialValue);
pane.setComponentOrientation(((parentComponent == null) ? JOptionPane
.getRootFrame() : parentComponent).getComponentOrientation());
final JDialog dialog = pane.createDialog(parentComponent, title);
pane.selectInitialValue();
dialog.setAlwaysOnTop(true);
dialog.show();
dialog.dispose();
Object selectedValue = pane.getValue();
if (selectedValue == null)
return JOptionPane.CLOSED_OPTION;
if (options == null) {
if (selectedValue instanceof Integer)
return ((Integer) selectedValue).intValue();
return JOptionPane.CLOSED_OPTION;
}
for (int counter = 0, maxCounter = options.length; counter < maxCounter; counter++) {
if (options[counter].equals(selectedValue))
return counter;
}
return JOptionPane.CLOSED_OPTION;
}
}
: