java: TrayIcon right click disabled on Mac OsX - java

I'm trying to develop a Mac OsX app provided by a system tray icon, so after the first attempt with the simplest code to achieve it I noticed that every apps tray icon's (both system and user apps) on mac osX (10.8) allows to activate the relative popup menu with both left and right click on it but with my project only the left (MouseEvent.BOTTON1) button causes the popup menu to pulldown. Here's my code:
public class SystemTrayDemo
{
private SystemTray tray;
private TrayIcon tray_icon;
public SystemTrayDemo()
{
if (!SystemTray.isSupported())
{
JOptionPane.showMessageDialog(null, "System tray not supported!");
return;
}
else
tray = SystemTray.getSystemTray();
final PopupMenu popup = new PopupMenu();
MenuItem exit = new MenuItem("Exit");
exit.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
if (tray != null)
{
tray.remove(tray_icon);
System.exit(0);
}
}
});
popup.add(exit);
//add tray icon
tray_icon = new TrayIcon(getIcon("images/wifi.png"), "Open documents...", popup);
tray_icon.setImageAutoSize(true);
try
{
tray.add(tray_icon); // adds icon
}
catch (AWTException ex) {}
}
private Image getIcon(String name)
{
URL _url = getClass().getResource(name);
return new ImageIcon(_url).getImage();
}
public static void main(String args[])
{
new SystemTrayDemo();
}
}
but how I already said, only through left mouse button click.
So during a further attempt I've tried to mimic the behavior of the tray icons of every other apps using a MouseListener and firing a left button event on right click event using dispatchEvent() method like so:
public static void fireMouseEvent(Component c)
{
MouseEvent me = new MouseEvent(c, // which
MouseEvent.MOUSE_CLICKED, // what
System.currentTimeMillis(), // when
MouseEvent.BUTTON1_MASK, // no modifiers
0, 0, // where: at (10, 10}
1, // only 1 click
true); // popup trigger
c.dispatchEvent(me);
}
the event will handled by the mouse listener but obviously TrayIcon Class is not a Component subclass and therefore the source of MouseEvent is null and I get a NPE. Here's my MouseListener:
class MouseAdapt extends java.awt.event.MouseAdapter
{
public void mouseClicked(java.awt.event.MouseEvent me)
{
int button = me.getButton();
if(button == java.awt.event.MouseEvent.BUTTON3)
{
fireMouseEvent(me.getComponent());
}
}
}
try
{
tray.add(tray_icon); // aggiungi l'icona
tray_icon.addMouseListener(new MouseAdapt());
}
catch (AWTException ex) {}
Sorry for my english, I hope that someone who have ever had some experience with that kind of projects can help me. I've searched for hours but with no luck. Thank You for your help.

Edit: There's now a library working to fix all of this here: https://github.com/dorkbox/SystemTray
to activate the [TrayIcon] relative popup menu with both left and right click
This is simply not possible on Mac + Java currently. Using reflection to invoke the underlying triggers doesn't seem to help. This is a bug.
https://bugs.openjdk.java.net/browse/JDK-8041890
only the left (MouseEvent.BOTTON1) button causes the popup menu to pulldown. Here's my code
Even this is broken in some Java versions (7u79), fixed with an upgrade...
https://bugs.openjdk.java.net/browse/JDK-7158615
Cross-Platform TrayIcon Support:
Albeit slightly off-topic, I wanted to add, some projects use a JXTrayIcon to accomplish some fancy drop-down menus in Linux/Windows, etc. These also cause problems on Mac despite a click-bug it already suffers from today as well as bugs with Gnome3 requiring a completely separate hack. But on Mac, any attempt to use the decorated menus causes the menu to linger and is a very bad experience for the end-user. The solution I settled on was to use AWT for Mac, Swing for everything else. The Java TrayIcon support is in dire need of a rewrite. JavaFX claims to help this initiative, but it's staged for Java 9. In the mean time, I'm sticking to OS-dependent hacks.
Related Tray Issues for Other Platforms
Furthermore, some Linux distributions like Ubuntu have removed the tray icon by default in the Unity desktop, causing further headaches. https://askubuntu.com/a/457212/412004
In addition, the transparency of the icon is replaced with a gray color on Gtk/Gnome or Qt/KDE powered desktops (Both OpenJDK and Oracle JRE suffer this)
https://stackoverflow.com/a/3882028/3196753
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6453521
In addition, Gnome3 powered desktops may show it in the wrong corner, not at all, or it may show but be unclickable (Both OpenJDK and Oracle JRE suffer this)
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=660157
https://bugzilla.redhat.com/show_bug.cgi?id=1014448
In addition to that, high-DPI screens on Windows have a bug that draws the icon incorrectly: Windows 8 Distorts my TrayIcon
So in summary, the state of the System Tray in Java is OK, but due to the combination of factors is quite fragmented and buggy in JDK6, JDK7 and JDK8.

Related

JavaFX Button onAction property does not fire when Button pressed on touchscreen

I'm learning JavaFX and working on a JavaFX application that will turn my laptop's touchscreen into a mini-piano. My prototype has a bunch of Buttons in place of piano keys, with each button mapped to a different Midi note. Clicking on a button with the mouse successfully triggers the button's onAction property and plays the associated note. Poking the button with my finger doesn't. The program clearly knows where my finger is because when I poke a button with my finger the button changes color, just as it does when I move the mouse pointer into it. I know that the problem is with JavaFX rather than with Java more generally or with my touchscreen because I wrote an essentially identical prototype in Swing where poking the screen succesfully plays a note. (I would gladly have stuck to Swing, too, if only Swing had any kind of multi-touch support. I want to play chords.) Is there something about JavaFX that I'm missing, such as a touchscreen event handler, or is something deeply wrong here?
For the record, I'm using OpenJDK 11.0.7 and OpenJFX 11.0.2 with a Xubuntu laptop. Here's the relevant bits of code.
#Override
public void start(Stage stage) {
stage.setTitle("Midi Test");
buttons = new Button[NOTE_VALUE.length];
for (int i = 0; i < NOTE_VALUE.length; i++) {
buttons[i] = new Button(NOTE_NAME[i]);
buttons[i].setPrefSize(KEY_WIDTH,KEY_HEIGHT);
buttons[i].setOnAction(this);
}
// Layout omitted for brevity
stage.show();
}
public void handle(ActionEvent event) {
// Identifies which button was pressed and plays the corresponding note
int index = -1;
for (int i = 0; i < buttons.length; i++) {
if (event.getSource().equals(buttons[i])) {
index = i;
break;
}
}
if (index != -1) {
channels[0].allNotesOff();
channels[0].noteOn(NOTE_VALUE[index],93);
}
}
After adopting #James_D's diagnostic suggestions (thanks, James) and doing some additional research, it looks like the problem is due to a known (but obscure) bug deep in the guts of OpenJFX 11. See the discussion here for details. There appear to be some workarounds, but the most straightforward solution would seem to be to try a more recent version of OpenJFX.

netbeans setDefaultCloseOperation

I am trying to set the default close operation in NetBeans 8.0.2 (in Ubuntu 14.04 on an older Asus gaming laptop.) My program is very large but uses no JFrame or java.swing components.
I merely need to save some values when the "x" in the lower right corner is clicked (this is one usual way to stop execution of a java program in NetBeans.)
I found suggestions that involved swing & JFrame, but it wasn't clear just where to insert the code:
DefaultApplicationView view = new DefaultApplicationView(this);
javax.swing.JFrame frame = view.getFrame();
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.addWindowListener(new WindowAdapter(){
public void WindowClosing(WindowEvent e){
System.out.println("CLOSING");
}
}
show(view);
I also found a set of instructions that I think I would prefer to use, but the post is old enough that my NetBeans doesn't have the tabs/menu-items referred to:
Set Window to Design Mode by clicking the 'Design' Tab
In the Navigator: Right click the 'JFrame' -> 'Properties'
In the Properties Tab: Set 'defaultCloseOperation' (top of the list) to 'DO_NOTHING'
Select 'Events' Tab
Scroll down to 'windowClosing'
Click on the "..." button on the right of the event to bring up the custom editor
Click 'Add...' and name the handler (i.e. custom function that you want to have execute on click of the 'X', or window close event).
Click 'Ok'
Netbeans now automatically creates the function and takes to you the function body in the source view
Now simply add what you want to do here: eg. dispose(), or system.exit or pintln(), or whatever your heart desires, as long as its JAVA and makes sense to the app.
Then there are a few other possibly relevant posts, but they all explicitly involve JFrame and/or swing. (Am I ignorant of some fact such as "All NetBeans java applications use JFrame", or some such?)
A pared down example of code for what I'm trying to do would be:
public class MyApp{
public static void main(String[] args){
loadMyVariables();
// do some work that changes variables' values
// during this work user clicks the 'x' box to halt execution
// I need then automatically to save the variables' new values
}
// needs to be called by the OS or GUI when execution is halted by user
public static void saveMyVariables{
// here the usual printStream stuff saves some values to a file
System.exit(0);
}
public static void loadMyVariables{
// here the usual Scanner stuff reads some values from a file
}
}
(I need help setting the tags for this, so I'm doing as instructed and asking the community.)
THANKS

Tray Icon not working on Ubuntu 16.04

I ran into an Issue with Java awt tray icons under Ubuntu Gnome 16.04:
The Icon is displayed in the top left corner of my screen and in the System Tray appears a black square. The MouseListener is also not working (neither on the icon nor on the black square).
Here is my Code:
if (SystemTray.isSupported()) {
Image image = ImageIO.read(EyeUNIFYlocal.class.getResource("/star.png"));
TrayIcon trayIcon = new TrayIcon(image);
trayIcon.setImageAutoSize(true);
trayIcon.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("Clicked");
}
});
try {
SystemTray.getSystemTray().add(trayIcon);
} catch (AWTException ex) {
System.err.println("Error while creating tray icon.");
}
} else {
System.err.println("Tray icons are not supported on this System.");
}
This code works fine on Windows 10.
Thank you in advance!
Java System Tray support doesn't exist for newer Linux distributions, mostly because of the changes from GtkStatusIcon to AppIndicator, and GTK2/3 changes as well (so, issues with JavaFX unless you install some additional libraries).
Additionally, since you mentioned Gnome -- Gnome likes to "hide" the AppIndicator as "notifications", so there is an extension (top-icons) that lets you restore the indicators back to the top of the screen (instead of in a hidden drawer at the bottom left of the screen)
If you want to display cross-platform system tray icons, I suggest the SystemTray project. There is an inbound 3.0 release soon (an API rewrite and better native support), but the older 2.x version should solve the problem you are having.

Display numbers on a tray icon with SWT

I would like to show some numbers on my tray icon indicating a number of events that happened to the user like what is done in this facebook notifications icons:
Do you think that it is possible ?
Thank you
You can do this using the TaskBar and TaskItem classes although it may not work on all platforms.
TaskBar taskBar = Display.getDefault().getSystemTaskBar();
// TODO may return null if not supported on the platform
// Get application item
TaskItem taskItem = taskBar.getItem(null);
if (taskItem != null)
taskItem.setOverlayText("your text");
Also try:
TaskItem taskItem = taskBar.getItem(shell);
where shell is your main application shell. The TaskItem JavaDoc suggests trying both methods of getting the TaskItem:
For better cross platform support, the application code should first
try to set this feature on the TaskItem for the main shell then on the
TaskItem for the application.

How to detect single clicks to System TrayIcon for Java App?

I'm working on a simple Java swing app, which adds an icon to the system tray when created. What I'm trying to do is to detect when this icon is single clicked by the user (whether through left click or right click), There's no popup menu, I just want the app to be restored when the icon is clicked.
This is the code I'm using:
SystemTray tray = SystemTray.getSystemTray();
Image icon = toolkit.getImage("icon.png");
ActionListener listener = new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
System.out.println("click detected");
}
};
TrayIcon trayIcon = new TrayIcon(icon, "Test Program", null);
trayIcon.addActionListener(listener);
tray.add(trayIcon);
What happens when I run this program though, is that single clicks (either left or right) have no effect, but when I double click, then it shows the message 'click detected' in the console.
What can I do to have single clicks also be detected? Do I need to use a MouseListener for this? ( I've heard that MouseListeners can cause problems, and ActionListeners are better)
You could use MouseListener, ie:
trayIcon.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 1) {
}
}
});
See How to Write a Mouse Listener for more details.
EDIT: ActionListener vs MouseListener
There is a concept of low level and semantic events. Whenever possible, you should listen for semantic events rather than low-level events, such as listening for action events, rather than mouse events. Read for more details in Low-Level Events and Semantic Events.
In this case you just need more details from the event so using MouseListener is required.

Categories

Resources