moses-palmer / pystray

GNU General Public License v3.0
463 stars 57 forks source link

How is the "Default" action specified? Can I detect when the icon has been double-clicked? #92

Closed PySimpleGUI closed 3 years ago

PySimpleGUI commented 3 years ago

I see some mention of default actions in the code and docs, but I'm struggling a bit.

Question on detection single / double-click of the icon

I would like to be informed of both single and double-click events of the icon, if possible.

I tried this technique.... I added a MenuItem that has the parm default set to True. I also set visible to False since it's not actually a menu item that I want shown. Here's the line of code I'm using.

        item = pystray.MenuItem(text='Default', action=default_action, visible=False, default=True, enabled=True)

image

I think I'm mixing up the meaning of "default".

If I single click the Tray Icon, I get this error message:

An error occurred when calling message handler
Traceback (most recent call last):
  File "C:\Python\Anaconda3\lib\site-packages\pystray\_win32.py", line 399, in _dispatcher
    uMsg, lambda w, l: 0)(wParam, lParam) or 0)
  File "C:\Python\Anaconda3\lib\site-packages\pystray\_win32.py", line 187, in _on_notify
    self()
  File "C:\Python\Anaconda3\lib\site-packages\pystray\_base.py", line 88, in __call__
    self._menu(self)
TypeError: 'list' object is not callable

What's the best way of setting up a handler for single and doublt-clicked events?


Notification Balloon Questions

A related "click" event is if clicking of the message balloon can generate an event. For Qt and WxPython, they both return an event when the message is clicked (if my memory is working right this morning).

I'm elated to have the ability to show a message at all!

image

Is it possible to show an icon next to the title?

Thank you! Great package as I'm sure you're aware, but I'm sure you likely never get tired of hearing those words either so I'm happy to say "thank you for the awesome package!"

darkcurrent commented 3 years ago

I'm struggling with the same double-click issue. Is there any update about it?

PySimpleGUI commented 3 years ago

I got some help from a friend that noticed I was setting things up incorrectly which took care of the error I was getting.

I still needed to implement my own double-click, but that was a relatively easy task.

I released my code to PyPI under the project named psgtray and I have a repo that matches:

https://github.com/PySimpleGUI/psgtray

Here is the isolated code that does the single and double click:

    def _default_action_callback(self):
        delta = (time.time() - self.double_click_timer) * 1000
        if delta < self.DOUBLE_CLICK_THRESHOLD:  # if last click was recent, then this click is a double-click
            self.window.write_event_value(self.key, sg.EVENT_SYSTEM_TRAY_ICON_DOUBLE_CLICKED)
            self.double_click_timer = 0
        else:
            if self.single_click_events_enabled:
                self.window.write_event_value(self.key, sg.EVENT_SYSTEM_TRAY_ICON_ACTIVATED)
            self.double_click_timer = time.time()

The method is called as the default action (when a single click happens). If there's a single click, then I save the time. If another click happens within the "Double Click Threshold" then I call it a double click. The threshold value I used was 500ms which seems to work well.

I'm really pleased that it's possible to run pystray as a thread now!! It's made it possible to use with PySimpleGUI in a really nice way. Big-time thank you to @moses-palmer for his hard work on this package!

moses-palmer commented 3 years ago

@darkcurrent, thank you for bringing my attention to this.

@PySimpleGUI, are you sure that you are using the menu icon constructor correctly? As noted in the documentation, the menu passed to the constructor must be an instance of pystray.Menu. This will ensure that non-visible items are indeed invisible, and that the default action works as expected.

Regarding notifications: at the moment, only displaying a notification with a message an a title is supported; no interactions nor custom icons are possible to attach.

EDIT: Turns out I was too slow in responding :-) I'm glad to hear that you managed to solve it yourself!

PySimpleGUI commented 3 years ago

Yes, I believe I am using the constructor correctly.

This is the docstring info:

image

And I'm calling with a list of MenuItems

        self.tray_icon.menu = pystray.Menu(*self.menu_items)

For example, the default item is added to this list with this line:

        menu_items.append(pystray.MenuItem('default', self._default_action_callback, enabled=True, default=True, visible=False))

The result is that the default is being called and it is also not visible in the menu.... both great things.

I've got no outstanding problems at this point. I had a request about icons and if clicks of the balloon were possible, but they're not "problems", just questions.

PySimpleGUI commented 3 years ago

One operation that i have not added is the ability to update the Menu once it's running.

Is that possible with the current implementation? I'm sorry if this is covered in the docs or examples. It's been over a month since I was actively working in this area and there's been a lot of other stuff that's overwritten that part of my brain's storage.

moses-palmer commented 3 years ago

Dynamic menus can be achieved by providing lambdas instead of concrete values for most attributes as noted in the documentation.