Giter VIP home page Giter VIP logo

infi.systray's Introduction

infi.systray

This module implements a Windows system tray icon with a right-click context menu.

Installation

To install infi.systray, run:

pip install infi.systray

Alternatively, you can use easy_install.

Usage

Creating an icon with one option in the context menu:

from infi.systray import SysTrayIcon
def say_hello(systray):
    print "Hello, World!"
menu_options = (("Say Hello", None, say_hello),)
systray = SysTrayIcon("icon.ico", "Example tray icon", menu_options)
systray.start()

The first parameter to SysTrayIcon is a path to the icon to show in the systray. If the icon is not found, or if None is specified, a default system icon will be displayed. The second parameter is the hover text to show when the mouse is hovered over the systray icon. The traybar will run in its own thread, so the using script can continue to run.

The icon and/or hover text can be updated using the update() method with the appropriate hover_text or icon keyword argument:

for item in ['item1', 'item2', 'item3']:
    systray.update(hover_text=item)
    do_something(item)

To destroy the icon when the program ends, call

systray.shutdown()

SysTrayIcon can be used as a context manager to start and shutdown the tray, which also prevents hung tray threads should the parent thread fail or otherwise not close the tray process:

with SysTrayIcon(icon, hover_text) as systray:
    for item in ['item1', 'item2', 'item3']:
        systray.update(hover_text=item)
        do_something(item)

A "Quit" command is always appended to the end of the icon context menu, after the menu options specified by the user. To perform operations when Quit is selected, pass "on_quit=callback" as a parameter, e.g.:

def on_quit_callback(systray):
    program.shutdown()
systray = SysTrayIcon("icon.ico", "Example tray icon", menu_options, on_quit=on_quit_callback)

When the user double-clicks the systray icon, the first option specified in menu_options will be executed. The default command may be changed to a different option by setting the parameter "default_menu_index", e.g.:

systray = SysTrayIcon("icon.ico", "Example tray icon", menu_options, default_menu_index=2)

menu_options must be a list of 3-tuples. Each 3-tuple specifies a context menu options. The first value in each tuple is the context menu string. Some versions of Windows can show icons next to each option in the context menu. This icon can be specified in the second value of the tuples. If None is passed, no icon is displayed for the option. The third value is the command to execute when the context menu is selected by the user.

It is possible to create sub-menus in the context menu by recursively passing a list of 3-tuple options as the third value of an option, instead of passing a callback function. e.g.

from infi.systray import SysTrayIcon
hover_text = "SysTrayIcon Demo"
def hello(sysTrayIcon):
    print "Hello World."
def simon(sysTrayIcon):
    print "Hello Simon."
def bye(sysTrayIcon):
    print 'Bye, then.'
def do_nothing(sysTrayIcon):
    pass
menu_options = (('Say Hello', "hello.ico", hello),
                ('Do nothing', None, do_nothing),
                ('A sub-menu', "submenu.ico", (('Say Hello to Simon', "simon.ico", simon),
                                               ('Do nothing', None, do_nothing),
                                              ))
               )
sysTrayIcon = SysTrayIcon("main.ico", hover_text, menu_options, on_quit=bye, default_menu_index=1)
sysTrayIcon.start()

Note that in the previous examples, if no code is executed after calling systray.start(), the main thread will exit and the icon thread will continue to exist until the Quit option is selected. In order to catch keyboard interrupts, some code must be written that will call systray.shutdown when the program should quit. Using SysTrayIcon as a context manager automates the start and shutdown of the tray.

This module can only be used in Windows systems, otherwise the import statement will fail.

Credit

This module is adapted from an implementation by Simon Brunning, which in turn was adapted from Mark Hammond's win32gui_taskbar.py and win32gui_menu.py demos from PyWin32.

Checking out the code

To run this code from the repository for development purposes, run the following:

easy_install -U infi.projector
projector devenv build

infi.systray's People

Contributors

grzn avatar loehnertj avatar onionradish avatar oryjonay avatar steffo99 avatar wiggin15 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

infi.systray's Issues

Broken on Windows 10?

I'm getting this error when simply running the following code:

    with SysTrayIcon("1.ico", "Example tray icon") as tray:
        do_something()
Exception in thread Thread-1:
Traceback (most recent call last):
  File "c:\python27\lib\threading.py", line 810, in __bootstrap_inner
    self.run()
  File "c:\python27\lib\threading.py", line 763, in run
    self.__target(*self.__args, **self.__kwargs)
  File "c:\python27\lib\site-packages\infi\systray\traybar.py", line 111, in _message_loop_func
    PumpMessages()
  File "c:\python27\lib\site-packages\infi\systray\win32_adapter.py", line 188, in PumpMessages
    TranslateMessage(ctypes.byref(msg))
ArgumentError: argument 1: <type 'exceptions.TypeError'>: expected LP_MSG instance instead of pointer to MSG

Fonts are blurred when scaling on highDPI monitors

When increasing windows scaling, the fonts get blurred. Please see below for a comparison between infi.systray and Powertoys' tray context menu at 100%, 125% and 200%:
Font scaling issue

Since this is all text I am rather confused to why infi.systray looks so poor!

Creating customized menu

Is there anyway to just receive the right and left click event, and do the rest of things myself?
I can get mouse position and show my own window in the suitable position instead of using Windwos-like menus.
I just need to make the tray, and receive click events, is such thing possible?

Increase the width of the systray box (for a larger icon or text box)?

I need to print some text in the systray. I currently print text in an image using Pillow on a 15px square icon, but I need a little bit more space for my text.

Is there a way to increase the systray box size, to fit a 30px15px icon? (Or, maybe to simply output some text in a larger systray box?).

The time/date on my systray is shown on a much bigger box in the systray, so it might be possible to increase the width of these systray boxes.

systray

Provide a way to skip adding the default Quit option

I would like a way to avoid adding the default Quit option. I have two reasons:

  1. As my application heads towards production I don't want it to have a Quit option. The application will terminate itself in certain circumstances.
  2. Right now I'm struggling with an issue that is causing deadlocks.

I don't fully understand the deadlock issue but it is bad interaction across threads and it is somehow related to the unique wiring that the "on_quit" option has. The short story is that this works perfectly:

server = ...
tray = SysTrayIcon(..., menu_options=(("Quit", None, server.cancel),))
tray._menu_options.pop()
with tray:
    await server.run()

While

server = ...
with SysTrayIcon(..., on_quit=server.cancel):
    await server.run()

causes deadlocks on context manager exit in any situation other than clicking the "Close" button on the menu, due to some internals of server.cancel().

Passing arguments for the function in menu_options.

Hi, i am pretty new to python.

I am not able to pass any argument to any of the functions that are in the menu_options tree?
Could someone explain how to do it?

When i click one of the options of the menu i want to call a function that needs two arguments but i am not able to pass them, it gives me an error, like if the function didn't accept any arguments.
And also whenever i run the project , the function in the menu_options tree always runs even though i dont click the button in the tray area for it run.

Thanks in advanced.

SysTrayIcon.shutdown produces threading join exception

Hey there,

Same issue as the one 2 years ago,

SystrayIcon.shutdown() produces a threading join error.

  File "C:\Users\bobmy\AppData\Local\Programs\Python\Python37\lib\site-packages\infi\systray\traybar.py", line 123, in shutdown
    self._message_loop_thread.join()
  File "C:\Users\bobmy\AppData\Local\Programs\Python\Python37\lib\threading.py", line 1041, in join
    raise RuntimeError("cannot join current thread")
RuntimeError: cannot join current thread```

Greets

updating menu options (maybe a feature request)

I have a script that can run either in mute mode and unmute mode. I would like to be able to switch between these two mode by right-clicking on the icon of my script in the systray menu and selecting a menu.
So far, the only way I could to do this with infi.systray is by having 2 menu options, one mute and the other one unmute.

Would it be possible to only have a single menu option whose label would be "mute" when my script is unmute and whose label would be unmute when my script is mute.

Maybe we could also have menu with checkmark. so the label would always be for instance mute and then with either a checkmark or not.

Thanks for sharing your work!

Icon not loading at windows start

Hello,

I have packaged my app with the SysTrayIcon, everything works exceptionally well except the icon.
Please note that I'm using pyinstaller to ship my app as an exe

When the app starts with the windows startup the icon is not loaded properly:
image

If I close the app, and open it again, it loads the icon properly, so it's very specific for windows startup.

Any suggestion how and what to debug?

image

how to pass parameter to menu option's function/command ?

it is a quick question: how to pass parameter to menu option's function/command ? Thanks.
like below:

def hello(sysTrayIcon, name):
    print "Hello "+name

menu_options = (('Say Hello', "hello.ico", hello('peter')), 
    ('Say Hello', "hello.ico", hello('jim')), ...
)

Is there way to remove the Quit command from the systray icon ?

I am working on a GUI Project and I do not want to use the Quit command from Systray Icon. Is there a way to that ?

I could see that QUIT is being added explicitly on the traybar.py. Any suggestions would help

menu_options = menu_options + (('Quit', None, SysTrayIcon.QUIT),)

Add method to override quit menu

Perhaps you add a method that would allow us to override quit menu option? Maybe not the behavior on click, but at least text+icon would be nice

How to make a check/uncheck option?

Can I make a menu option that can be checked and unchecked?

i.e. a "run on startup" option that when checked enables the program to do so and if unchecked it does the contrary...

How to add a specific order to tray icons?

mysys0=SysTrayIcon('1.ico', change_var, menu_options)
mysys0.start()
mysys1=SysTrayIcon('2.ico', change_var, menu_options)
mysys1.start()
mysys2=SysTrayIcon('3.ico', change_var, menu_options)
mysys2.start()

I'm trying to set together a 3 character number with these tray icons. But when I would wanna spawn the number "291" for example it spawns my tray icons in a completly random order (example:. 219 or 129), I have no clue how to influence it's order in systray. How do I solve this issue?

Pop-up bubble/balloon notification (feature request)

FEATURE REQUEST

I use this module to call some background scripting that is hidden to the user. I am working on having the tray icon color changing while the script is in progress and then back when it finishes, audio feedback, etc. It would be great to have the option of a pop-up notification/balloon where it could show the user the background script had completed.

Really like the module, thanks for all the hard work.

_load_icon picks wrong resolution

The _load_icon function specifies LR_DEFAULTSIZE flag, which gives 32x32 if available. This is particularly noticeable if an .ico file contains different images for different resolutions.

Instead it should use GetSystemMetrics(SM_CXSMICON) / GetSystemMetrics(SM_CYSICON) to get the right size for the system. Code can be copy-pasted from _prep_menu_icon function which already does this.

left-click to show the menu

Is there a way to make the program display the menu when you left-click on the system tray icon instead of right-clicking on it (or both)?

How to use default Quit option to quit my application instead of quitting only infi.systray?

Right now I have Python application running in background. When I Click on default Quit option it only closes the infi.systray icon but my application keeps running in background. I have also made my own function to quit the entire application and clear the memory and I can create a new option to run that function, but then there will be 2 quit buttons in the options i which is not acceptable.

I have 2 options to proceed with:

  1. Use my own function after removing default Quit button from menu_options.
  2. Map my own function on default Quit button somehow.

Any help in achieving either of these 2 will be helpful.

Packaging broken with cx_Freeze or PyInstaller

  • Issue: Packaging a simple systray project with cx_Freeze or PyInstaller breaks when building with the following error (last 3 traceback calls)
    File "C:\Python27\lib\site-packages\cx_Freeze\freezer.py", line 342, in _GetModuleFinder finder.IncludePackage(name) File "C:\Python27\lib\site-packages\cx_Freeze\finder.py", line 659, in IncludePackage module = self._ImportModule(name, deferredImports) File "C:\Python27\lib\site-packages\cx_Freeze\finder.py", line 351, in _ImportModule raise ImportError("No module named %r" % name) ImportError: No module named 'infi.systray'

  • Steps to reproduce:

  1. Make a simple project with infi.systray to show a tray icon (any simple sample project will do)

  2. Try to package that with PyInstaller or cx_Freeze to try and get a binary

  3. When running the command, the build breaks as it is unable to find the infi.systray package.

  • Suspect:

The naming seems to be the problem since it works well with all other pip libraries. Or maybe a namespace issue.

ModuleNotFoundError: No module named 'infi.systray'

Hi,
I tested your demo code in Python 3.7.7 on Windows 10:

from infi.systray import SysTrayIcon
def say_hello(systray):
    print("Hello, World!")
menu_options = (("Say Hello", None, say_hello),)
systray = SysTrayIcon("icon.ico", "Example tray icon", menu_options)
systray.start()

And I get this error message:
ModuleNotFoundError: No module named 'infi.systray'

Error with systray.shutdown()

Traceback (most recent call last):
  File "_ctypes/callbacks.c", line 237, in 'calling callback function'
  File "C:\Users\jorda\AppData\Local\Programs\Python\Python38-32\lib\site-packages\infi\systray\traybar.py", line 79, in WndProc
    self._message_dict[msg](hwnd, msg, wparam.value, lparam.value)
  File "C:\Users\jorda\AppData\Local\Programs\Python\Python38-32\lib\site-packages\infi\systray\traybar.py", line 195, in _destroy
    self._on_quit(self)
  File "d:/coding/python/mouse-milage/mouse-milage.py", line 9, in qcallback
    systray.shutdown()
  File "C:\Users\jorda\AppData\Local\Programs\Python\Python38-32\lib\site-packages\infi\systray\traybar.py", line 123, in shutdown
    self._message_loop_thread.join()
  File "C:\Users\jorda\AppData\Local\Programs\Python\Python38-32\lib\threading.py", line 1008, in join
    raise RuntimeError("cannot join current thread")
RuntimeError: cannot join current thread

Code:

import win32gui
from infi.systray import SysTrayIcon
from time import sleep
import sys

def say_hello(systray):
    print("Hello, World!")

def qcallback(systray):
    systray.shutdown()
    sys.exit()

menu_options = (("Say Hello", None, say_hello),)
systray = SysTrayIcon("icon.ico", "Example tray icon", menu_options, on_quit=qcallback)
systray.start()

while 1:

    i = 1

Not sure what happens, but this also appears to thoroughly bone the parent process. Terminal will accept ctrl+x but then no further input.

I have a problem executing a pyinstaller .exe of my script

First, Thanks for the support on this module it is amazing and fulfilled all my needs.
So, I made a script that every hour I request on openweather.com my city's weather, more especifically the temperature, in which I create a Image using image builder and write the number of degrees and then I save the temp.ico and then I update the icon on the systray. You can take a look on the code right here: https://github.com/Werner1201/TempSysTray, (I know there's some security issues but I just made it for fun, And I plan to make I better)
The issue is when I run it on through a .cmd file it works fine, but when I make a pyinstaller --onefile src/main.py and run the .exe I doesn't stay executing it just vanishes. Can you help me find the problem ?

How to add text after tray icon.

Hi, i have project battery monitoring, and i need add percentage value of battery after tray icon.
how to add text after tray icon looks like this:

image

thanks

How can I include this package into exe by pyinstaller

Thank you for developing this module.

But now I have a problem, maybe it has little to do with the project itself, and if someone like me has the same problem, maybe we can all get help.
It's about pyinstaller.

I try to put the package file in the same folder of pyw file,
or use the command:
pyinstaller --hidden-import=infi.systray usbdbp.pyw
also I tried:
pyinstaller usbdbp.pyw -p D:\Python27\Lib\site-packages

There is no way to solve this problem.

btw: My development environment is
95 INFO: PyInstaller: 3.1
95 INFO: Python: 2.7.12
96 INFO: Platform: Windows-7-6.1.7601-SP1

Thx for any help~

Not quite Python 3 compatible

Would be nice if it were. It actually gets as far as displaying the icon in the systray, but dies when you hover... by "dies" I mean something goes wrong, the icon disappears, but not the thread or the python. Must kill it in task manager.

From glancing over the source, it seems likely that it has something to do with Unicode strings, although many seem to get converted to ASCII (and I don't have non-ASCII strings in the menu).

Make "menu_options" an optional parameter

For use cases where custom system tray menu options are not required, allow the menu_options parameter to be optional (default as None), and only add them if supplied. Something like:

if menu_options: 
    menu_options = menu_options + (('Quit', None, self.QUIT),)
else:
    menu_options = (('Quit', None, self.QUIT),)

In several implementations, I use the icon to display the script status (whether running or not, specific processing stages, etc.) and do not need any custom menu options at all. Making the parameter optional would be preferable. Thanks!

Add public method to change icon, hover_text

Please consider adding an public method to change the tray icon and hover_text . They can currently be changed easily enough using the _refresh_icon() private method:

systray.icon = "icon2.ico"
systray.hover_text = "Example tray icon 2"
systray._refresh_icon()

With that minor request, I'd like to share my great appreciation for this script. I've been looking for a simple method to add a Windows system tray/notification area icon to scripts for a long time. This is the first one I've seen that doesn't require creating an entire app with a full GUI framework like wxPython/PyQt, and manually setting up non-blocking threading and semaphores for it and the main script. It only takes a few lines of inserted code to add a really valuable indicator that a script is running, its current status, etc. Thank you!

Conflict with win10toast

When I run the following code, when the toast notification ends, the systray application closes.

from infi.systray import SysTrayIcon
from win10toast import ToastNotifier
notifier = ToastNotifier()

def show_notif(systray):
    notifDuration = 5
    notifier.show_toast("Example Notification","Body",duration=notifDuration)
menu_options = (
    ("Show Notif",None,show_notif),
)
systray = SysTrayIcon("icon.ico", "Program name", menu_options)
systray.start()

This is using the version I got when I did pip install infi.systray and pip install win10toast

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.