pythonpysimpleguisystem-tray

calling sg.popup when SystemTray (psgtray) running


import PySimpleGUI as sg
from psgtray import SystemTray
import pyaudio 
import threading

def findAudioDevices():
    p = pyaudio.PyAudio()
    info = p.get_host_api_info_by_index(0)
    numdevices = info.get('deviceCount')
    device_info = ""
    for i in range(0, numdevices):
        if (p.get_device_info_by_host_api_device_index(0, i).get('maxInputChannels')) > 0:
            device_info += f"Input Device ID {i} - {p.get_device_info_by_host_api_device_index(0, i).get('name')}\n"
    sg.popup('Audio Devices', device_info)


# PySimpleGUI setup
menu_def = ['File', ['Show Audio Devices', 'Open Config', 'Exit']]
tooltip = 'Tooltip'

# Initialize the tray
tray = SystemTray(menu=menu_def, single_click_events=False, tooltip=tooltip, icon=r'Icon.png')
tray.show_message('Sound Switch', 'Sound Switchs Started!')

# Event loop
while True:
    menu_item = tray.key
    if menu_item == 'Exit':
        break
    elif menu_item == 'Show Audio Devices':
        findAudioDevices()  # This function should probably be modified to display a popup instead of printing to console
    elif menu_item == 'Open Config':
        os.system(f"notepad {config_path}")

tray.close()

leads to this error

An error occurred when calling message handler
Traceback (most recent call last):
  File "C:\Users\willwade\.pyenv\pyenv-win\versions\3.11.4\Lib\site-packages\pystray\_win32.py", line 398, in _dispatcher
    return int(icon._message_handlers.get(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\willwade\.pyenv\pyenv-win\versions\3.11.4\Lib\site-packages\pystray\_win32.py", line 210, in _on_notify
    descriptors[index - 1](self)
  File "C:\Users\willwade\.pyenv\pyenv-win\versions\3.11.4\Lib\site-packages\pystray\_base.py", line 308, in inner
    callback(self)
  File "C:\Users\willwade\.pyenv\pyenv-win\versions\3.11.4\Lib\site-packages\pystray\_base.py", line 434, in __call__
    return self._action(icon, self)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\willwade\.pyenv\pyenv-win\versions\3.11.4\Lib\site-packages\psgtray\psgtray.py", line 138, in _on_clicked
    self.window.write_event_value(self.key, item.text)
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'write_event_value'

So it looks like its ignoring sg and using psgtray - but I dont get it. I have a feeling its something to do with the window thread but I have no idea how to fix this?


Solution

  • It looks like you removed the code for the hidden window, also no value for option window when initiate the SystemTray.

    The PySimpleGUI architecture implemented the tray icon using the psgtray package combined with the overall window event loop, a Window object is still required.

    Revised code to

    import os
    import PySimpleGUI as sg
    from psgtray import SystemTray
    import pyaudio
    import threading
    
    def findAudioDevices():
        p = pyaudio.PyAudio()
        info = p.get_host_api_info_by_index(0)
        numdevices = info.get('deviceCount')
        device_info = ""
        for i in range(0, numdevices):
            if (p.get_device_info_by_host_api_device_index(0, i).get('maxInputChannels')) > 0:
                device_info += f"Input Device ID {i} - {p.get_device_info_by_host_api_device_index(0, i).get('name')}\n"
        sg.popup('Audio Devices', device_info)
    
    
    # PySimpleGUI setup
    menu_def = ['File', ['Show Audio Devices', 'Open Config', 'Exit']]
    tooltip = 'Tooltip'
    
    layout = [[sg.T('Empty Window', key='-T-')]]
    
    window = sg.Window('Window Title', layout, finalize=True, enable_close_attempted_event=True, alpha_channel=0)
    window.hide()
    
    # Initialize the tray
    tray = SystemTray(menu=menu_def, single_click_events=False, tooltip=tooltip, window=window)
    tray.show_message('Sound Switch', 'Sound Switchs Started!')
    
    # Event loop
    while True:
    
        event, values = window.read()
    
        menu_item = values[event]
    
        if menu_item == 'Exit':
            break
        elif menu_item == 'Show Audio Devices':
            findAudioDevices()  # This function should probably be modified to display a popup instead of printing to console
        elif menu_item == 'Open Config':
            sg.popup(menu_item)
            # os.system(f"notepad {config_path}")
    
    tray.close()
    window.close()