python --windos系统托盘pystray/自实现
- pip install pystray
-
示例
- import os
- import signal
- import subprocess
- import tempfile
-
- def open_chromium():
- '''系统托盘重启界面'''
- temp_profile_dir = os.path.join(tempfile.gettempdir(), "flaskwebgui")
-
- launch_options = [f"--window-size=1300,800"]
-
- options = [
- get_default_chrome_path(),
- f"--user-data-dir={temp_profile_dir}",
- "--new-window",
- "--no-first-run",
- ] + launch_options + [f'--app=http://127.0.0.1:8001']
-
- subprocess.Popen(options, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
-
-
- def _kill():
- ThreadPid.update(query={'arrange_id': 1}, data={'status': 0})
- logger.error('调用用户退出')
- handle = os.getpid()
- logger.error(f'pid={handle}')
- os.kill(handle, signal.SIGABRT)
-
- image = Image.open('logo.ico')
- icon = pystray.Icon('Neural', image, menu=pystray.Menu(
- pystray.MenuItem('打开主界面', open_chromium),
- pystray.MenuItem('退出', _kill)))
-
- icon.run_detached() #【注】 后台运行(必须有父进程)
- # ThreadPid.update(query={'arrange_id': 1}, data={'status': 1})
- # icon.run() #【注】 阻塞运行;
-
- from PIL import Image
-
- import pystray
-
- image = Image.open('logo.ico')
- icon = pystray.Icon('Neural', image, title='11', menu=pystray.Menu(
- pystray.MenuItem('打开主界面', lambda x: print(1), default=True), # 鼠标被单击事件
- pystray.Menu.SEPARATOR,
-
- pystray.MenuItem('退出', lambda x: print(2)),
- pystray.Menu.SEPARATOR,
-
- ))
-
-
- icon.run() # 【注】 此方式为阻塞
-
- import win32con
- import win32gui
- import time
- import abc
- from threading import Thread
-
- class Pystray(object):
- '''windows添加系统托盘'''
-
- def __init__(self, ico_path: str, ico_class_name: str, window_name: str='mywindowclass'):
- '''
- @params ico_path --> 系统托盘图标路径;
- @params ico_class_name --> 图标名;
- @params window_name --> 窗口类(非必要);
- '''
- self._ico_path: str = ico_path
- self._ico_class_name = ico_class_name
- self.__window_name = window_name
- self._menu = {} # {1024: ('菜单名', fun1), 1025: ('菜单名1', fun2)}
-
- @property
- def menu(self): return self._menu
-
- @menu.setter
- def menu(self, value: dict):
- if isinstance(value, dict):
- self._menu.update(value)
- else:
- raise TypeError('参数必须为字典;{1024: (菜单名, fun1), 1025: (菜单名1, fun2)}')
-
- @abc.abstractmethod
- def left_doubleclick(self):
- '''鼠标左键双击事件'''
- print("鼠标左键被双击了")
-
- @abc.abstractmethod
- def left_click(self):
- '''鼠标左键单击事件'''
- print("鼠标左键被单击了")
-
- @abc.abstractmethod
- def right_doubleclick(self):
- '''鼠标右键双击事件'''
- print("鼠标右键被双击了!")
-
- def _create_window(self):
- '''创建window对象'''
- wc = win32gui.WNDCLASS()
- self.hinst = wc.hInstance = win32gui.GetModuleHandle(None)
- wc.lpszClassName = self.__window_name
- wc.lpfnWndProc = self.wndProc
- self.classAtom = win32gui.RegisterClass(wc)
-
- def create_tray_icon(self):
- '''创建图标'''
- self._create_window()
- self.hwnd = win32gui.CreateWindow(self.classAtom, self.__window_name, win32con.WS_OVERLAPPED | win32con.WS_SYSMENU, 0, 0,
- win32con.CW_USEDEFAULT, win32con.CW_USEDEFAULT, 0, 0, self.hinst, None)
-
- icon_flags = win32con.LR_LOADFROMFILE | win32con.LR_DEFAULTSIZE
- hicon = win32gui.LoadImage(self.hinst, self._ico_path, win32con.IMAGE_ICON, 0, 0, icon_flags)
-
- # 设置系统托盘图标的属性
- flags = win32gui.NIF_ICON | win32gui.NIF_MESSAGE | win32gui.NIF_TIP
- nid = (self.hwnd, 0, flags, win32con.WM_USER + 20, hicon, self._ico_class_name)
- win32gui.Shell_NotifyIcon(win32gui.NIM_ADD, nid)
-
- @abc.abstractmethod
- def wndProc(self, hwnd, msg, wparam, lparam):
- ''' 定义系统托盘图标的消息处理函数'''
- if msg == win32con.WM_USER + 20: # 监听系统托盘图标的消息
- if lparam == win32con.WM_LBUTTONDBLCLK: # 监听鼠标左键双击事件
- self.left_doubleclick()
-
- elif lparam == win32con.WM_RBUTTONDOWN: # 监听右键单击事件
- # 显示右键菜单
- menu = win32gui.CreatePopupMenu()
- # for k, v in self._menu.items():
- # ids, name = k, v[0]
- # win32gui.AppendMenu(menu, win32con.MF_STRING, ids, name)
- win32gui.AppendMenu(menu, win32con.MF_STRING, 1023, "菜单项1")
- win32gui.AppendMenu(menu, win32con.MF_STRING, 1024, "菜单项2")
- win32gui.AppendMenu(menu, win32con.MF_STRING, 1025, "退出")
- pos = win32gui.GetCursorPos()
- win32gui.SetForegroundWindow(hwnd)
- win32gui.TrackPopupMenu(menu, win32con.TPM_LEFTALIGN, pos[0], pos[1], 0, hwnd, None)
- win32gui.PostMessage(hwnd, win32con.WM_NULL, 0, 0)
-
- elif lparam == win32con.WM_LBUTTONDOWN: # 监听鼠标左键单击事件
- self.left_click()
-
- elif lparam == win32con.WM_RBUTTONDBLCLK: # 监听右键双击事件
- self.right_doubleclick()
-
- elif msg == win32con.WM_COMMAND:
- id = win32gui.LOWORD(wparam)
- if id == 1023:
- print("执行菜单项1的操作")
- elif id == 1024:
- print("执行菜单项2的操作")
- elif id == 1025:
- win32gui.DestroyWindow(hwnd)
- return win32gui.DefWindowProc(hwnd, msg, wparam, lparam)
-
- def run(self):
- '''消息循环(正常启动)'''
- self.create_tray_icon()
- while True:
- time.sleep(0.1)
- win32gui.PumpWaitingMessages()
-
- def run_detached(self):
- '''非阻塞(须有父进程)'''
- t = Thread(target=a.run)
- t.daemon = True
- t.start()
-
- if __name__ == "__main__":
- a = Pystray('logo.ico', 'edg')
- # a.run()
- a.run_detached()
-