How do I determine the position of the taskbar on the screen?
So, I want to display JPopupMenu
when the user clicks the icon on the taskbar. However, the taskbar can be anywhere on the screen - bottom, top, right, left.
How can I determine where the sys tray is so that I can display the popup? getX()
and getY()
can get the coordinates of the click. Can the math be done to display the popup correctly?
Simple explanation and sample code would be appreciated.
Also, if the taskbar is hidden, an exception is thrown when I add TrayIcon
in SystemTray
?
source to share
There is no real way to do this inside Swing natively, however you can find a possible location with the following ...
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());
What are the outputs
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]
For my system (mind you, my taskbar is at the top of the screen)
Update
As shown in my previous answer to your question about tray icons ...
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;
}
}
source to share
I think you cannot determine the location in the system tray, but you can get all the location and size of the taskbar. You have to use WINAPI (shell32.dll).
See this:
How do I get the position and size of the taskbar?
This is an example in C #, but WINAPI is available in java.
You can find information about Java + WINAPI here:
source to share
I followed the approach from Kamil to get the size of the taskbar using JNA and Win32 DLL. The mechanism seems to be working to detect the taskbar, but that forces you to get the exact position of the icon.
JNA code using links provided by Kamil implemented in Java:
package at.cone.core.tray;
import java.awt.Rectangle;
import com.sun.jna.Native;
import com.sun.jna.platform.win32.Shell32;
import com.sun.jna.platform.win32.ShellAPI.APPBARDATA;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef.DWORD;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinDef.UINT;
import com.sun.jna.platform.win32.WinDef.UINT_PTR;
public class SystemTray {
private static final String TASKBAR_CLASSNAME = "Shell_TrayWnd";
private static UINT_PTR UINT_PTR_ZERO = new UINT_PTR(0);
/*
* See
* https://msdn.microsoft.com/en-us/library/windows/desktop/bb762108(v=vs.85).
* aspx
*/
private static DWORD ABS_ALWAYSONTOP = new DWORD(0x2);
private static DWORD ABM_GETSTATE = new DWORD(0x4);
private static DWORD ABM_GETTASKBARPOS = new DWORD(0x5);
private static DWORD ABM_GETAUTOHIDEBAR = new DWORD(0x7);
static {
System.setProperty("jna.library.path", YOUR_PATH_TO_JNA_DLLS);
}
private UINT position;
private Rectangle bounds;
private boolean alwaysOnTop;
private boolean autoHide;
public SystemTray() {
HWND hTaskbar = User32.INSTANCE.FindWindow(TASKBAR_CLASSNAME, null);
APPBARDATA data = new APPBARDATA();
data.cbSize = new DWORD(Native.getNativeSize(APPBARDATA.class));// (uint) Marshal.SizeOf(typeof(APPBARDATA));
data.hWnd = hTaskbar;
UINT_PTR result = Shell32.INSTANCE.SHAppBarMessage(ABM_GETTASKBARPOS, data);
if (result == UINT_PTR_ZERO)
throw new IllegalStateException();
this.position = (UINT) data.uEdge;
this.bounds = new Rectangle(data.rc.left, data.rc.top, data.rc.right - data.rc.left,
data.rc.bottom - data.rc.top);
data.cbSize = new DWORD(Native.getNativeSize(APPBARDATA.class));
result = Shell32.INSTANCE.SHAppBarMessage(ABM_GETSTATE, data);
long state = result.longValue();
this.alwaysOnTop = (state & ABS_ALWAYSONTOP.longValue()) == ABS_ALWAYSONTOP.longValue();
this.autoHide = (state & ABM_GETAUTOHIDEBAR.longValue()) == ABM_GETAUTOHIDEBAR.longValue();
}
public Rectangle getBounds() {
return bounds;
}
}
But this implementation mainly considers the position of the taskbar. The exact mechanism for icon positioning can still be improved - see https://social.msdn.microsoft.com/Forums/windows/en-US/4ac8d81e-f281-4b32-9407-e663e6c234ae/how-to-get-screen-coordinates -of-notifyicon? forum = winforms
source to share