Cómo construir un SystemTray aplicación para Windows?

Yo por lo general trabajan en un sistema Linux, pero estoy en una situación donde tengo que escribir una aplicación cliente que se podría ejecutar en windows como un servicio. Alguien me puede ayudar o directamente, sobre cómo crear una Barra de menú de la aplicación ( por ejemplo, dropbox) para el entorno de windows, que se inicia en el inicio del SO y el icono se encuentra en la Barra de tareas y hacer clic en el icono de la aplicación presenta un menú.

Mi lenguaje de scripting es python. Gracias.

  • Se le suele llamar la «bandeja del sistema», no «de la barra de menú’, probablemente, usted debe actualizar su pregunta a reflejar eso.
  • Se llama el área de notificación, no de la bandeja del sistema …
  • Actualizado a la pregunta, gracias.
  • He visto que se llama: kb.iu.edu/data/aiat.html . Técnicamente, usted parece ser correcta, aunque.

3 Kommentare

  1. 30

    Esto se hace mediante el pywin32 (Python para Windows Extensions) módulo.

    Ejemplo de Código de Python 2

    Pregunta Similar

    Para hacer que se ejecute al inicio, usted podría tener un lío con los servicios, pero que en realidad es mucho más fácil de instalar un enlace para el archivo exe en la que los usuarios «Carpeta de Inicio».

    Windows 7 y Vista

    c:\Users\[nombre de usuario]\AppData\Roaming\Microsoft\Windows\Menú Inicio\Programas\Inicio

    Windows XP

    c:\Documents and Settings\[nombre de usuario]\Menú Inicio\Programas\Inicio

  2. 14

    He modificado el SysTrayIcon.py Secuencia de comandos de Python 2 para trabajar en Python 3

    • Que usted necesita para instalar pip install pywin32.
    • Después de que usted necesita para ejecutar python Scripts/pywin32_postinstall.py -install desde el directorio de Python para registrar la dll.
    • Para la prueba de secuencia de comandos a ejecutar, es necesario tener algunos *.ico archivos en su directorio de trabajo – usted puede encontrar un montón de ellos en su c:\windows* carpetas (búsqueda de file:.ico).
    • Para ocultar el programa, se puede ejecutar a través de pythonw.exe.
    • Si usted necesita globo de notificaciones, eche un vistazo a este post: https://stackoverflow.com/a/42085439/2441026 (Plyer paquete).
    • Tener un menú con sólo el botón Salir que usted necesita para pasar menu_options = ((None, None, None),) – (o cambiar la clase a la que no siempre anexar menu_options).

    #!/usr/bin/env python
    # Module     : SysTrayIcon.py
    # Synopsis   : Windows System tray icon.
    # Programmer : Simon Brunning - [email protected] - modified for Python 3
    # Date       : 13 February 2018
    # Notes      : Based on (i.e. ripped off from) Mark Hammond's
    #              win32gui_taskbar.py and win32gui_menu.py demos from PyWin32
    '''TODO
    
    For now, the demo at the bottom shows how to use it...'''
    
    import os
    import sys
    import win32api         # package pywin32
    import win32con
    import win32gui_struct
    try:
        import winxpgui as win32gui
    except ImportError:
        import win32gui
    
    class SysTrayIcon(object):
        '''TODO'''
        QUIT = 'QUIT'
        SPECIAL_ACTIONS = [QUIT]
    
        FIRST_ID = 1023
    
        def __init__(self,
                     icon,
                     hover_text,
                     menu_options,
                     on_quit=None,
                     default_menu_index=None,
                     window_class_name=None,):
    
            self.icon = icon
            self.hover_text = hover_text
            self.on_quit = on_quit
    
            menu_options = menu_options + (('Quit', None, self.QUIT),)
            self._next_action_id = self.FIRST_ID
            self.menu_actions_by_id = set()
            self.menu_options = self._add_ids_to_menu_options(list(menu_options))
            self.menu_actions_by_id = dict(self.menu_actions_by_id)
            del self._next_action_id
    
    
            self.default_menu_index = (default_menu_index or 0)
            self.window_class_name = window_class_name or "SysTrayIconPy"
    
            message_map = {win32gui.RegisterWindowMessage("TaskbarCreated"): self.restart,
                           win32con.WM_DESTROY: self.destroy,
                           win32con.WM_COMMAND: self.command,
                           win32con.WM_USER+20 : self.notify,}
            # Register the Window class.
            window_class = win32gui.WNDCLASS()
            hinst = window_class.hInstance = win32gui.GetModuleHandle(None)
            window_class.lpszClassName = self.window_class_name
            window_class.style = win32con.CS_VREDRAW | win32con.CS_HREDRAW;
            window_class.hCursor = win32gui.LoadCursor(0, win32con.IDC_ARROW)
            window_class.hbrBackground = win32con.COLOR_WINDOW
            window_class.lpfnWndProc = message_map # could also specify a wndproc.
            classAtom = win32gui.RegisterClass(window_class)
            # Create the Window.
            style = win32con.WS_OVERLAPPED | win32con.WS_SYSMENU
            self.hwnd = win32gui.CreateWindow(classAtom,
                                              self.window_class_name,
                                              style,
                                              0,
                                              0,
                                              win32con.CW_USEDEFAULT,
                                              win32con.CW_USEDEFAULT,
                                              0,
                                              0,
                                              hinst,
                                              None)
            win32gui.UpdateWindow(self.hwnd)
            self.notify_id = None
            self.refresh_icon()
    
            win32gui.PumpMessages()
    
        def _add_ids_to_menu_options(self, menu_options):
            result = []
            for menu_option in menu_options:
                option_text, option_icon, option_action = menu_option
                if callable(option_action) or option_action in self.SPECIAL_ACTIONS:
                    self.menu_actions_by_id.add((self._next_action_id, option_action))
                    result.append(menu_option + (self._next_action_id,))
                elif non_string_iterable(option_action):
                    result.append((option_text,
                                   option_icon,
                                   self._add_ids_to_menu_options(option_action),
                                   self._next_action_id))
                else:
                    print('Unknown item', option_text, option_icon, option_action)
                self._next_action_id += 1
            return result
    
        def refresh_icon(self):
            # Try and find a custom icon
            hinst = win32gui.GetModuleHandle(None)
            if os.path.isfile(self.icon):
                icon_flags = win32con.LR_LOADFROMFILE | win32con.LR_DEFAULTSIZE
                hicon = win32gui.LoadImage(hinst,
                                           self.icon,
                                           win32con.IMAGE_ICON,
                                           0,
                                           0,
                                           icon_flags)
            else:
                print("Can't find icon file - using default.")
                hicon = win32gui.LoadIcon(0, win32con.IDI_APPLICATION)
    
            if self.notify_id: message = win32gui.NIM_MODIFY
            else: message = win32gui.NIM_ADD
            self.notify_id = (self.hwnd,
                              0,
                              win32gui.NIF_ICON | win32gui.NIF_MESSAGE | win32gui.NIF_TIP,
                              win32con.WM_USER+20,
                              hicon,
                              self.hover_text)
            win32gui.Shell_NotifyIcon(message, self.notify_id)
    
        def restart(self, hwnd, msg, wparam, lparam):
            self.refresh_icon()
    
        def destroy(self, hwnd, msg, wparam, lparam):
            if self.on_quit: self.on_quit(self)
            nid = (self.hwnd, 0)
            win32gui.Shell_NotifyIcon(win32gui.NIM_DELETE, nid)
            win32gui.PostQuitMessage(0) # Terminate the app.
    
        def notify(self, hwnd, msg, wparam, lparam):
            if lparam==win32con.WM_LBUTTONDBLCLK:
                self.execute_menu_option(self.default_menu_index + self.FIRST_ID)
            elif lparam==win32con.WM_RBUTTONUP:
                self.show_menu()
            elif lparam==win32con.WM_LBUTTONUP:
                pass
            return True
    
        def show_menu(self):
            menu = win32gui.CreatePopupMenu()
            self.create_menu(menu, self.menu_options)
            #win32gui.SetMenuDefaultItem(menu, 1000, 0)
    
            pos = win32gui.GetCursorPos()
            # See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/menus_0hdi.asp
            win32gui.SetForegroundWindow(self.hwnd)
            win32gui.TrackPopupMenu(menu,
                                    win32con.TPM_LEFTALIGN,
                                    pos[0],
                                    pos[1],
                                    0,
                                    self.hwnd,
                                    None)
            win32gui.PostMessage(self.hwnd, win32con.WM_NULL, 0, 0)
    
        def create_menu(self, menu, menu_options):
            for option_text, option_icon, option_action, option_id in menu_options[::-1]:
                if option_icon:
                    option_icon = self.prep_menu_icon(option_icon)
    
                if option_id in self.menu_actions_by_id:                
                    item, extras = win32gui_struct.PackMENUITEMINFO(text=option_text,
                                                                    hbmpItem=option_icon,
                                                                    wID=option_id)
                    win32gui.InsertMenuItem(menu, 0, 1, item)
                else:
                    submenu = win32gui.CreatePopupMenu()
                    self.create_menu(submenu, option_action)
                    item, extras = win32gui_struct.PackMENUITEMINFO(text=option_text,
                                                                    hbmpItem=option_icon,
                                                                    hSubMenu=submenu)
                    win32gui.InsertMenuItem(menu, 0, 1, item)
    
        def prep_menu_icon(self, icon):
            # First load the icon.
            ico_x = win32api.GetSystemMetrics(win32con.SM_CXSMICON)
            ico_y = win32api.GetSystemMetrics(win32con.SM_CYSMICON)
            hicon = win32gui.LoadImage(0, icon, win32con.IMAGE_ICON, ico_x, ico_y, win32con.LR_LOADFROMFILE)
    
            hdcBitmap = win32gui.CreateCompatibleDC(0)
            hdcScreen = win32gui.GetDC(0)
            hbm = win32gui.CreateCompatibleBitmap(hdcScreen, ico_x, ico_y)
            hbmOld = win32gui.SelectObject(hdcBitmap, hbm)
            # Fill the background.
            brush = win32gui.GetSysColorBrush(win32con.COLOR_MENU)
            win32gui.FillRect(hdcBitmap, (0, 0, 16, 16), brush)
            # unclear if brush needs to be feed.  Best clue I can find is:
            # "GetSysColorBrush returns a cached brush instead of allocating a new
            # one." - implies no DeleteObject
            # draw the icon
            win32gui.DrawIconEx(hdcBitmap, 0, 0, hicon, ico_x, ico_y, 0, 0, win32con.DI_NORMAL)
            win32gui.SelectObject(hdcBitmap, hbmOld)
            win32gui.DeleteDC(hdcBitmap)
    
            return hbm
    
        def command(self, hwnd, msg, wparam, lparam):
            id = win32gui.LOWORD(wparam)
            self.execute_menu_option(id)
    
        def execute_menu_option(self, id):
            menu_action = self.menu_actions_by_id[id]      
            if menu_action == self.QUIT:
                win32gui.DestroyWindow(self.hwnd)
            else:
                menu_action(self)
    
    def non_string_iterable(obj):
        try:
            iter(obj)
        except TypeError:
            return False
        else:
            return not isinstance(obj, str)
    
    # Minimal self test. You'll need a bunch of ICO files in the current working
    # directory in order for this to work...
    if __name__ == '__main__':
        import itertools, glob
    
        icons = itertools.cycle(glob.glob('*.ico'))
        hover_text = "SysTrayIcon.py Demo"
        def hello(sysTrayIcon): print("Hello World.")
        def simon(sysTrayIcon): print("Hello Simon.")
        def switch_icon(sysTrayIcon):
            sysTrayIcon.icon = next(icons)
            sysTrayIcon.refresh_icon()
        menu_options = (('Say Hello', next(icons), hello),
                        ('Switch Icon', None, switch_icon),
                        ('A sub-menu', next(icons), (('Say Hello to Simon', next(icons), simon),
                                                      ('Switch Icon', next(icons), switch_icon),
                                                     ))
                       )
        def bye(sysTrayIcon): print('Bye, then.')
    
        SysTrayIcon(next(icons), hover_text, menu_options, on_quit=bye, default_menu_index=1)
  3. 8

    Hay (al menos) un par de bibliotecas abiertamente disponibles para esta ahora:

    Acabo de empezar a utilizar infi.systray en un proyecto, y ha funcionado bien para mí. He aquí cómo poco código que usted necesita para hacer algo muy básico (tomado de sus docs):

    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()

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea