Closed mrgreywater closed 1 year ago
I think I did this by design so as not to confuse folks that may see the getTrayIcon
method and not understand the AWT bits. Let me check my notes on this. Sub-classing FXTrayIcon might be preferable if you're dabbling around with the internals.
@mrgreywater
Here's an example of subclassing FXTrayIcon then from that subclass, setting up a listener for the right mouse button event:
import com.dustinredmond.fxtrayicon.FXTrayIcon;
import javafx.stage.Stage;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
public class TrayIcon extends FXTrayIcon {
public TrayIcon(Stage parentStage, File iconFile, int iconWidth, int iconHeight) {
super(parentStage, iconFile, iconWidth, iconHeight);
}
public void setMouseListener() {
getTrayIcon().addMouseListener(new MouseListener() {
@Override public void mouseClicked(MouseEvent e) {
if(e.getButton() == 3) {
System.out.println("User right clicked on tray icon");
}
}
@Override public void mousePressed(MouseEvent e) {
}
@Override public void mouseReleased(MouseEvent e) {
}
@Override public void mouseEntered(MouseEvent e) {
}
@Override public void mouseExited(MouseEvent e) {
}
});
}
}
And here is how you would use it:
File file = new File(pathToMyIconFile);
TrayIcon tray = new TrayIcon(stage,file,24,24);
tray.addExitItem("Exit");
tray.setMouseListener();
tray.show();
And here's what happens when the icon is right clicked:
User right clicked on tray icon
Thank you. Yes I'm doing something similar right now as I indicated. I still think just exposing the underlying Tray Icon would make it more straight forward.
As is I had to investigate the source code to find a way to attach that callback. Autocomplete doesn't show the getTrayIcon function as it is only available in the inherited context. Making it public would make it more "self-documenting" in my opinion.
@mrgreywater When you're extending a class, then all of the protected methods of the class you're extending will be available in the extended (sub)class... with IntelliJ Idea those methods show up in autocomplete as you can see here
Also, you could create in the subclass, a public method that returns the AWT TrayIcon object ... you can even expose the builder class and pick and chose which constructors you want to include in that exposed class...
import com.dustinredmond.fxtrayicon.FXTrayIcon;
import javafx.stage.Stage;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.net.URL;
public class TrayIcon extends FXTrayIcon {
public TrayIcon(Stage parentStage, File iconFile, int iconWidth, int iconHeight) {
super(parentStage, iconFile, iconWidth, iconHeight);
}
public void setMouseListener() {
getTrayIcon().addMouseListener(new MouseListener() {
@Override public void mouseClicked(MouseEvent e) {
if(e.getButton() == 3) {
System.out.println("User right clicked on tray icon");
}
}
@Override public void mousePressed(MouseEvent e) {
}
@Override public void mouseReleased(MouseEvent e) {
}
@Override public void mouseEntered(MouseEvent e) {
}
@Override public void mouseExited(MouseEvent e) {
}
});
}
public java.awt.TrayIcon trayIcon() {
return super.trayIcon;
}
public static class Builder extends FXTrayIcon.Builder {
public Builder(Stage parentStage, URL iconImagePath, int iconWidth, int iconHeight) {
super(parentStage, iconImagePath, iconWidth, iconHeight);
}
}
}
From there, you would just use your extended subclass in your application instead of using the library's FXTrayIcon class directly.
@mrgreywater It looks like I was mistaken about exposing the TrayIcon awt object. It's not accessible outside of the subclassed context... but that shouldn't be a big deal since there really shouldn't be a need to access that object outside of that class in the first place. But when I tried exposing it, the IDE barked at me reminding me that no matter how I try to make it available outside of that class, I can go pound sand cause its not gonna happen.
I even tried making it an object within the subclass, then setting it equal to the protected get method then with a different method exposing it from there, but its protected status follows it where it's used so then the only way to accomplish that would be to possibly instantiate a new awt.TrayIcon object and then copy that one to the new one if that can even be done.
But like I said once you have it in the subclass... it really shouldn't be necessary to access it outside of the subclass.
@mrgreywater I submitted a PR that I think will meet the original design intent of protecting the object while also providing a way of accessing it without needing to extend the main class. Ultimately it's up to Dustin if he wants to accept the PR, but I think he might like the solution that I proposed.
I much prefer what #74 does. If one is comfortable enough to use the AWT TrayIcon, I didn't envision them as using the FXTrayIcon library. I was mistaken on this, and could definitely see how folks may want to hack around with the AWT object. Planning on merging this PR. Thanks @EasyG0ing1!
@dustinkredmond @mrgreywater I already have a custom right-click option on an app I wrote that gives me access to my One Time Password keys right from the system tray. Now I can just right-click on it instead of navigating the menu to have the keys just pop up with that single click. I had wanted to do this from the beginning but just assumed I couldn't and never dug into it until this issue was opened. I'm loving the evolution of this library ... though I'm still waiting for the day when we will get native JavaFX access to the system tray, though I'm not holding my breath on that one.
Currently there is no simple way to get the underlying java.awt.TrayIcon. As such you cannot do essential things such as checking if a user right clicked the tray icon.
As a workaround, you can inherit from FXTrayIcon and expose getTrayIcon with a different function name.