awheel のアドバイスを拡張して、Swing のガラス ペイン機能を使用する次の例を作成しました。このアプローチは少し面倒ですが、Swing である程度高度なものを試している場合は、これは珍しいことではありません。
ボタンをクリックすると透明なオーバーレイ パネル (ウィンドウの内容全体を覆うガラス ペイン) を表示し、ユーザーがウィンドウ内の任意の場所をクリックするか、キーを押すと、それを破棄するという考え方です。
このガラス ペインの上に、別の JPanel (「ポップアップ」) を表示し、その可視性をトリガーするボタンのすぐ上に配置しようとします。
このアプローチには、元のダイアログ ベースのソリューションにない制限が 1 つあります。ガラス ペインの上に描画されるものはすべて、フレームのコンテンツ領域内に収まる必要があります (結局のところ、それはウィンドウではありません)。そのため、以下のコードで popup< の座標がコンテンツ ペインの境界内にあることを確認するためにいくつかの調整を行います (そうしないと、JLabel はフレームの端で単純にトリミングされます)。
また、ガラス ペインによってキャッチされたマウス プレスが、基になるコンポーネントに委任されないという制限もあります。したがって、ガラス ペインが表示されているときにボタンをクリックすると、ガラス ペインは消えますが、クリックも消費され、クリックしたはずのボタンが反応しなくなります。必要に応じてこれを回避することもできますが、さらに複雑になるため、例を比較的単純にしたいと考えました。:-)
java.awt.Color をインポートします。
java.awt.Container をインポートします。
java.awt.FlowLayout をインポートします。
java.awt.KeyEventDispatcher をインポートします。
java.awt.KeyboardFocusManager をインポートします。
import java.awt.Point;
java.awt.Window をインポートします。
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
java.awt.event.MouseAdapter をインポートします。
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JDialog;
javax.swing.JFrame をインポートします。
javax.swing.JLabel をインポートします。
javax.swing.JPanel をインポートします。
import javax.swing.JRootPane;
javax.swing.SwingUtilities をインポートします。
import javax.swing.border.BevelBorder;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
public class GlassPaneTest extends JFrame {
public static class PropertiesButton extends JButton {
/** 現在表示されているガラス ペイン。
* 何も表示されない場合は null にする必要があります。*/
プライベート JPanel theGlassPane;
/** 接続されたウィンドウのルート ペイン。ガラス板の貼り付けに使用。*/
private final JRootPane rootPane;
/** 接続されたウィンドウのコンテンツ ペイン。座標計算に使用されます。*/
プライベート最終コンテナ contentPane;
/* ガラス板が表示されているときにキーの押下をインターセプトできるようにする「キー フック」、
* ガラス板を隠すことができます。*/
private final KeyEventDispatcher keyHook = new KeyEventDispatcher() {
public boolean dispatchKeyEvent(KeyEvent e) {
if (theGlassPane == null || e.getID() != KeyEvent.KEY_PRESSED) {
false を返します。
}
setGlassPaneVisible(false);
true を返します。
}
};
public PropertiesButton(ウィンドウの親ウィンドウ) {
if (!(JFrame の親ウィンドウ インスタンス || JDialog の親ウィンドウ インスタンス)) {
throw new IllegalArgumentException("JFrame または JDialog インスタンスのみが受け入れられます");
}
if (parentWindow instanceof JDialog) {
rootPane = ((JDialog) parentWindow).getRootPane();
contentPane = ((JDialog) parentWindow).getContentPane();
} そうしないと {
rootPane = ((JFrame) parentWindow).getRootPane();
contentPane = ((JFrame) parentWindow).getContentPane();
}
addActionListener(新しいActionListener() {
public void actionPerformed(ActionEvent e) {
setGlassPaneVisible(theGlassPane == null);
}
});
}
プライベート JPanel createGlassPane() {
// ガラス ペインを透明なレイアウトのないパネルとして作成します
// (絶対配置を許可するため)、コンテンツ ペイン全体をカバーします。
// マウスを押すと消えます。
JPanel gp = 新しい JPanel();
gp = 新しい JPanel();
gp.setOpaque(false);
gp.setLayout(null);
gp.setBounds(contentPane.getBounds());
gp.addMouseListener(new MouseAdapter() {
@オーバーライド
public void mousePressed(MouseEvent e) {
setGlassPaneVisible(false);
}
});
// 「ポップアップ」を作成します - 透明に表示されるコンポーネント
// かぶせる。
JPanel popup = new JPanel();
popup.setBorder(新しい CompoundBorder(
new BevelBorder(BevelBorder.RAISED),
new EmptyBorder(5, 5, 5, 5)));
popup.setBackground(Color.YELLOW);
popup.add(new JLabel("\" の情報"" + getText() + "\"."));
// ガラス ペインにはレイアウト マネージャーがないため必要です。
popup.setSize(popup.getPreferredSize());
// トリガーされたボタンのすぐ上にポップアップを配置します
// その可視性。
Point buttonLocationInContentPane = SwingUtilities.convertPoint(this, 0, 0, contentPane);
int x = buttonLocationInContentPane.x;
int horizOverlap = x + popup.getWidth() - contentPane.getWidth();
if (horizOverlap > 0) {
x -= horizOverlap;
}
int y = buttonLocationInContentPane.y - popup.getHeight();
もし (y < 0) {
y = 0;
}
popup.setLocation(x, y);
gp.add(ポップアップ);
gp を返します。
}
private void setGlassPaneVisible(boolean visible) {
キーボード フォーカス マネージャー kfm = キーボード フォーカス マネージャー.getCurrentKeyboardFocusManager();
もし (見える) {
theGlassPane = createGlassPane();
rootPane.setGlassPane(theGlassPane);
theGlassPane.setVisible(真);
kfm.addKeyEventDispatcher(keyHook);
} そうしないと {
theGlassPane.setVisible(false);
kfm.removeKeyEventDispatcher(keyHook);
theGlassPane = null;
}
}
}
// 簡単なテスト プログラム
public GlassPaneTest() {
setTitle("ガラス板の例");
setLayout(新しい FlowLayout(FlowLayout.CENTER));
for (int i = 1; i <= 10; ++i) {
PropertiesButton pb = 新しい PropertiesButton(this);
pb.setText("プロパティ ボタン" + i);
追加 (pb);
}
setSize(400, 300);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame f = new GlassPaneTest();
f.setDefaultCloseOperation(EXIT_ON_CLOSE);
f.setVisible(真);
}
});
}
}