JPopupMenuがTaskBarと重ならないように表示位置を調整する
Total: 694
, Today: 2
, Yesterday: 0
Posted by aterai at
Last-modified:
概要
JPopupMenu
がTaskBar
と重なる場合、マウスカーソル位置がその右下隅になるよう表示位置を調整し、内部のJMenuItem
の配置も反転します。
Screenshot
Advertisement
サンプルコード
List<Component> list = Arrays.asList(
new JMenuItem("JMenuItem 1"),
new JMenuItem("JMenuItem 2"),
new JMenuItem("JMenuItem 3"),
new JMenuItem("JMenuItem 4"),
new JMenuItem("JMenuItem 5"));
JPopupMenu popup = new JPopupMenu() {
@Override public void show(Component c, int x, int y) {
Point popupLocation = getInvokerOrigin(x, y, c.getLocationOnScreen());
Rectangle scrBounds = getScreenBounds(c, popupLocation);
Dimension popupSize = getPreferredSize();
long popupBottomY = (long) popupLocation.y + (long) popupSize.height;
Point p = new Point(x, y);
removeAll();
if (popupBottomY > scrBounds.y + scrBounds.height) {
p.translate(-popupSize.width, -popupSize.height);
for (int i = list.size() - 1; i >= 0; i--) {
add(list.get(i));
}
} else {
list.forEach(this::add);
}
super.show(c, p.x, p.y);
}
};
list.forEach(popup::add);
setComponentPopupMenu(popup);
View in GitHub: Java, Kotlin解説
JPopupMenu
の親コンポーネントが表示されているGraphicsConfiguration
を取得JPopupMenu#getCurrentGraphicsConfiguration(Point)
を参考
GraphicsConfiguration getCurrentGraphicsConfiguration2(Component c, Point p) {
GraphicsConfiguration gc = null;
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice[] gd = ge.getScreenDevices();
for (GraphicsDevice graphicsDevice : gd) {
if (graphicsDevice.getType() == GraphicsDevice.TYPE_RASTER_SCREEN) {
GraphicsConfiguration dgc = graphicsDevice.getDefaultConfiguration();
if (dgc.getBounds().contains(p)) {
gc = dgc;
break;
}
}
}
// If not found, and we have invoker, ask invoker about his gc
if (gc == null && c != null) {
gc = c.getGraphicsConfiguration();
}
return gc;
}
- 取得した
GraphicsConfiguration
からスクリーン領域を取得しTaskBar
などの余白を除去- デフォルトの
JPopupMenu
ではJPopupMenu#adjustPopupLocationToFitScreen(int xPosition, int yPosition)
メソッド内で( (SunToolkit) Toolkit.getDefaultToolkit() ).canPopupOverlapTaskBar()
がfalse
の場合TaskBar
などの余白を除去してスクリーン領域サイズを計算しているがWindows 10
環境では常にtrue
でこれを変更する方法が不明 - このためこのサンプルでは以下のように
( (SunToolkit) Toolkit.getDefaultToolkit() ).canPopupOverlapTaskBar()
を無視してTaskBar
領域をスクリーン領域サイズから除去している
- デフォルトの
private static Rectangle getScreenBounds(Component c, Point popupLocation) {
Rectangle scrBounds;
GraphicsConfiguration gc = getCurrentGraphicsConfiguration2(c, popupLocation);
Toolkit toolkit = Toolkit.getDefaultToolkit();
if (gc != null) {
// If we have GraphicsConfiguration use it to get screen bounds
scrBounds = gc.getBounds();
} else {
scrBounds = new Rectangle(toolkit.getScreenSize());
}
Insets scrInsets = toolkit.getScreenInsets(gc);
scrBounds.x += scrInsets.left;
scrBounds.y += scrInsets.top;
scrBounds.width -= scrInsets.left + scrInsets.right;
scrBounds.height -= scrInsets.top + scrInsets.bottom;
return scrBounds;
}
JPopupMenu#show(...)
をオーバーライドして取得したスクリーン領域の外にJPopupMenu
の下辺が表示される場合は、マウスカーソル位置がJPopupMenu
の右下隅になるよう表示位置を調整- 左上隅から右下隅にマウスカーソル配置が変更されるので
JPopupMenu
内部のJMenuItem
の配置もマウスカーソル移動距離が短くなるよう昇順から降順に変更 JPopupMenu#show(...)
内などで参照されているpopupPostionFixDisabled
はpopupPositionFixDisabled
のtypo
?
- 左上隅から右下隅にマウスカーソル配置が変更されるので