所以我想JPopupMenu在用户单击系统托盘中的图标时显示.但是,任务栏可以位于屏幕上的任何位置 - 底部,顶部,右侧,左侧.

如何确定sys托盘的位置以便显示弹出窗口?
getX()并getY()可以获得点击的坐标.可以做一些数学运算来正确显示弹出窗口吗?
一个简单的解释和示例代码将不胜感激.
此外,如果任务栏被隐藏,当我添加TrayIcon到SystemTray?时会生成异常吗?
在Swing本机中没有真正的方法可以做到这一点,但是,您可以使用以下内容推导出可能的位置...
GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
Rectangle bounds = gd.getDefaultConfiguration().getBounds();
Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gd.getDefaultConfiguration());
Rectangle safeBounds = new Rectangle(bounds);
safeBounds.x += insets.left;
safeBounds.y += insets.top;
safeBounds.width -= (insets.left + insets.right);
safeBounds.height -= (insets.top + insets.bottom);
System.out.println("Bounds = " + bounds);
System.out.println("SafeBounds = " + safeBounds);
Area area = new Area(bounds);
area.subtract(new Area(safeBounds));
System.out.println("Area = " + area.getBounds());
Run Code Online (Sandbox Code Playgroud)
哪个输出
Bounds = java.awt.Rectangle[x=0,y=0,width=2560,height=1600]
SafeBounds = java.awt.Rectangle[x=0,y=40,width=2560,height=1560]
Area = java.awt.Rectangle[x=0,y=0,width=2560,height=40]
Run Code Online (Sandbox Code Playgroud)
对于我的系统(注意,我的任务栏位于屏幕顶部)
更新
正如我之前关于托盘图标的问题的回答所示......
public class TestTaskIcon {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
Image img = null;
try {
img = ImageIO.read(new File("floppy_disk_red.png"));
} catch (IOException e) {
e.printStackTrace();
}
TrayIcon ti = new TrayIcon(img, "Tooltip");
ti.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
Rectangle bounds = getSafeScreenBounds(e.getPoint());
JPopupMenu popup = new JPopupMenu();
popup.add(new JLabel("hello"));
Point point = e.getPoint();
int x = point.x;
int y = point.y;
if (y < bounds.y) {
y = bounds.y;
} else if (y > bounds.y + bounds.height) {
y = bounds.y + bounds.height;
}
if (x < bounds.x) {
x = bounds.x;
} else if (x > bounds.x + bounds.width) {
x = bounds.x + bounds.width;
}
if (x + popup.getPreferredSize().width > bounds.x + bounds.width) {
x = (bounds.x + bounds.width) - popup.getPreferredSize().width;
}
if (y + popup.getPreferredSize().height > bounds.y + bounds.height) {
y = (bounds.y + bounds.height) - popup.getPreferredSize().height;
}
popup.setLocation(x, y);
popup.setVisible(true);
}
});
try {
SystemTray.getSystemTray().add(ti);
} catch (AWTException ex) {
Logger.getLogger(TestTaskIcon.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
public static Rectangle getSafeScreenBounds(Point pos) {
Rectangle bounds = getScreenBoundsAt(pos);
Insets insets = getScreenInsetsAt(pos);
bounds.x += insets.left;
bounds.y += insets.top;
bounds.width -= (insets.left + insets.right);
bounds.height -= (insets.top + insets.bottom);
return bounds;
}
public static Insets getScreenInsetsAt(Point pos) {
GraphicsDevice gd = getGraphicsDeviceAt(pos);
Insets insets = null;
if (gd != null) {
insets = Toolkit.getDefaultToolkit().getScreenInsets(gd.getDefaultConfiguration());
}
return insets;
}
public static Rectangle getScreenBoundsAt(Point pos) {
GraphicsDevice gd = getGraphicsDeviceAt(pos);
Rectangle bounds = null;
if (gd != null) {
bounds = gd.getDefaultConfiguration().getBounds();
}
return bounds;
}
public static GraphicsDevice getGraphicsDeviceAt(Point pos) {
GraphicsDevice device = null;
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice lstGDs[] = ge.getScreenDevices();
ArrayList<GraphicsDevice> lstDevices = new ArrayList<GraphicsDevice>(lstGDs.length);
for (GraphicsDevice gd : lstGDs) {
GraphicsConfiguration gc = gd.getDefaultConfiguration();
Rectangle screenBounds = gc.getBounds();
if (screenBounds.contains(pos)) {
lstDevices.add(gd);
}
}
if (lstDevices.size() > 0) {
device = lstDevices.get(0);
} else {
device = ge.getDefaultScreenDevice();
}
return device;
}
}
Run Code Online (Sandbox Code Playgroud)
我认为您无法确定系统托盘位置,但您可以获得整个任务栏的位置和大小.你必须使用WINAPI(shell32.dll).
看到这个:
这是C#中的示例,但WINAPI在java中可用.
在这里您可以找到有关Java + WINAPI的信息: