网上的SysTrayIcon改的,Tk页面最小化至托盘,托盘图标左键单击恢复Tk界面
1.点击最小化隐藏至托盘

2.托盘图标右键菜单展示,左键返回Tk界面。

托盘图标可以自定义,修改了SysTrayIcon更容易调用,Demo窗口加了注释,具体查看 _Main 类。

2020.12.11更新:添加了气泡提示,修改了两个函数名

代码如下:

import win32api, win32con, win32gui_struct, win32gui
import os, tkinter as tkclass SysTrayIcon (object):'''SysTrayIcon类用于显示任务栏图标'''QUIT = 'QUIT'SPECIAL_ACTIONS = [QUIT]FIRST_ID = 5320def __init__(s, icon, hover_text, menu_options, on_quit, tk_window = None, default_menu_index=None, window_class_name = None):'''icon         需要显示的图标文件路径hover_text   鼠标停留在图标上方时显示的文字menu_options 右键菜单,格式: (('a', None, callback), ('b', None, (('b1', None, callback),)))on_quit      传递退出函数,在执行退出时一并运行tk_window    传递Tk窗口,s.root,用于单击图标显示窗口default_menu_index 不显示的右键菜单序号window_class_name  窗口类名'''s.icon = icons.hover_text = hover_texts.on_quit = on_quits.root = tk_windowmenu_options = menu_options + (('退出', None, s.QUIT),)s._next_action_id = s.FIRST_IDs.menu_actions_by_id = set()s.menu_options = s._add_ids_to_menu_options(list(menu_options))s.menu_actions_by_id = dict(s.menu_actions_by_id)del s._next_action_ids.default_menu_index = (default_menu_index or 0)s.window_class_name = window_class_name or "SysTrayIconPy"message_map = {win32gui.RegisterWindowMessage("TaskbarCreated"): s.restart,win32con.WM_DESTROY : s.destroy,win32con.WM_COMMAND : s.command,win32con.WM_USER+20 : s.notify ,}# 注册窗口类。wc = win32gui.WNDCLASS()wc.hInstance = win32gui.GetModuleHandle(None)wc.lpszClassName = s.window_class_namewc.style = win32con.CS_VREDRAW | win32con.CS_HREDRAW;wc.hCursor = win32gui.LoadCursor(0, win32con.IDC_ARROW)wc.hbrBackground = win32con.COLOR_WINDOWwc.lpfnWndProc = message_map #也可以指定wndproc.s.classAtom = win32gui.RegisterClass(wc)def activation(s):'''激活任务栏图标,不用每次都重新创建新的托盘图标'''hinst = win32gui.GetModuleHandle(None)# 创建窗口。style = win32con.WS_OVERLAPPED | win32con.WS_SYSMENUs.hwnd = win32gui.CreateWindow(s.classAtom, s.window_class_name, style,0, 0, win32con.CW_USEDEFAULT, win32con.CW_USEDEFAULT,0, 0, hinst, None)win32gui.UpdateWindow(s.hwnd)s.notify_id = Nones.refresh(title = '软件已后台!', msg = '点击重新打开', time = 500)win32gui.PumpMessages()def refresh(s, title = '', msg = '', time = 500):'''刷新托盘图标title 标题msg   内容,为空的话就不显示提示time  提示显示时间'''hinst = win32gui.GetModuleHandle(None)if os.path.isfile(s.icon):icon_flags = win32con.LR_LOADFROMFILE | win32con.LR_DEFAULTSIZEhicon = win32gui.LoadImage(hinst, s.icon, win32con.IMAGE_ICON,0, 0, icon_flags)else: # 找不到图标文件 - 使用默认值hicon = win32gui.LoadIcon(0, win32con.IDI_APPLICATION)if s.notify_id: message = win32gui.NIM_MODIFYelse: message = win32gui.NIM_ADDs.notify_id = (s.hwnd, 0, # 句柄、托盘图标IDwin32gui.NIF_ICON | win32gui.NIF_MESSAGE | win32gui.NIF_TIP | win32gui.NIF_INFO,  #托盘图标可以使用的功能的标识win32con.WM_USER + 20, hicon, s.hover_text,  # 回调消息ID、托盘图标句柄、图标字符串msg, time, title,   # 提示内容、提示显示时间、提示标题win32gui.NIIF_INFO  # 提示用到的图标)win32gui.Shell_NotifyIcon(message, s.notify_id)def show_menu(s):'''显示右键菜单'''menu = win32gui.CreatePopupMenu()s.create_menu(menu, s.menu_options)pos = win32gui.GetCursorPos()win32gui.SetForegroundWindow(s.hwnd)win32gui.TrackPopupMenu(menu,win32con.TPM_LEFTALIGN,pos[0],pos[1],0,s.hwnd,None)win32gui.PostMessage(s.hwnd, win32con.WM_NULL, 0, 0)def _add_ids_to_menu_options(s, menu_options):result = []for menu_option in menu_options:option_text, option_icon, option_action = menu_optionif callable(option_action) or option_action in s.SPECIAL_ACTIONS:s.menu_actions_by_id.add((s._next_action_id, option_action))result.append(menu_option + (s._next_action_id,))else:result.append((option_text,option_icon,s._add_ids_to_menu_options(option_action),s._next_action_id))s._next_action_id += 1return resultdef restart(s, hwnd, msg, wparam, lparam):s.refresh()def destroy(s, hwnd = None, msg = None, wparam = None, lparam = None, exit = 1):nid = (s.hwnd, 0)win32gui.Shell_NotifyIcon(win32gui.NIM_DELETE, nid)win32gui.PostQuitMessage(0) # 终止应用程序。if exit and s.on_quit: s.on_quit() #需要传递自身过去时用 s.on_quit(s)else: s.root.deiconify()  #显示tk窗口def notify(s, hwnd, msg, wparam, lparam):'''鼠标事件'''if lparam==win32con.WM_LBUTTONDBLCLK:# 双击左键passelif lparam==win32con.WM_RBUTTONUP:  # 右键弹起s.show_menu()elif lparam==win32con.WM_LBUTTONUP:  # 左键弹起s.destroy(exit = 0)return True"""可能的鼠标事件:WM_MOUSEMOVE      #光标经过图标WM_LBUTTONDOWN    #左键按下WM_LBUTTONUP      #左键弹起WM_LBUTTONDBLCLK  #双击左键WM_RBUTTONDOWN    #右键按下WM_RBUTTONUP      #右键弹起WM_RBUTTONDBLCLK  #双击右键WM_MBUTTONDOWN    #滚轮按下WM_MBUTTONUP      #滚轮弹起WM_MBUTTONDBLCLK  #双击滚轮"""def create_menu(s, menu, menu_options):for option_text, option_icon, option_action, option_id in menu_options[::-1]:if option_icon:option_icon = s.prep_menu_icon(option_icon)if option_id in s.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()s.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(s, 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)brush = win32gui.GetSysColorBrush(win32con.COLOR_MENU)win32gui.FillRect(hdcBitmap, (0, 0, 16, 16), brush)win32gui.DrawIconEx(hdcBitmap, 0, 0, hicon, ico_x, ico_y, 0, 0, win32con.DI_NORMAL)win32gui.SelectObject(hdcBitmap, hbmOld)win32gui.DeleteDC(hdcBitmap)return hbmdef command(s, hwnd, msg, wparam, lparam):id = win32gui.LOWORD(wparam)s.execute_menu_option(id)def execute_menu_option(s, id):menu_action = s.menu_actions_by_id[id]      if menu_action == s.QUIT:win32gui.DestroyWindow(s.hwnd)else:menu_action(s)class _Main:  #调用SysTrayIcon的Demo窗口def __init__(s):s.SysTrayIcon  = None  # 判断是否打开系统托盘图标def main(s):#tk窗口s.root = tk.Tk()s.root.bind("<Unmap>", lambda event: s.Hidden_window() if s.root.state() == 'iconic' else False) #窗口最小化判断,可以说是调用最重要的一步s.root.protocol('WM_DELETE_WINDOW', s.exit) #点击Tk窗口关闭时直接调用s.exit,不使用默认关闭s.root.resizable(0,0)  #锁定窗口大小不能改变s.root.mainloop()def switch_icon(s, _sysTrayIcon, icon = 'D:\\2.ico'):#点击右键菜单项目会传递SysTrayIcon自身给引用的函数,所以这里的_sysTrayIcon = s.sysTrayIcon#只是一个改图标的例子,不需要的可以删除此函数_sysTrayIcon.icon = icon_sysTrayIcon.refresh()#气泡提示的例子s.show_msg(title = '图标更换', msg = '图标更换成功!', time = 500)def show_msg(s, title = '标题', msg = '内容', time = 500):s.SysTrayIcon.refresh(title = title, msg = msg, time = time)def Hidden_window(s, icon = 'D:\\1.ico', hover_text = "SysTrayIcon.py Demo"):'''隐藏窗口至托盘区,调用SysTrayIcon的重要函数'''#托盘图标右键菜单, 格式: ('name', None, callback),下面也是二级菜单的例子#24行有自动添加‘退出’,不需要的可删除menu_options = (('一级 菜单', None, s.switch_icon),  ('二级 菜单', None, (('更改 图标', None, s.switch_icon), )))s.root.withdraw()   #隐藏tk窗口if not s.SysTrayIcon: s.SysTrayIcon = SysTrayIcon(icon,               #图标hover_text,         #光标停留显示文字menu_options,       #右键菜单on_quit = s.exit,   #退出调用tk_window = s.root, #Tk窗口)s.SysTrayIcon.activation()def exit(s, _sysTrayIcon = None):s.root.destroy()print ('exit...')if __name__ == '__main__':Main = _Main()Main.main()

SysTrayIcon 改的 python tkinter 最小化至系统托盘相关推荐

  1. MFC最小化到系统托盘

    在VC++中,想实现将MFC最小化到系统托盘,需要调用NOTIFYICONDATA类,并注册相应的消息,以下详细讲解如何实现: 第一步,声明一个NOTIFYICONDATA类,也就是NOTIFYICO ...

  2. 将 VMware 最小化到系统托盘

    1, 下载 Trayconizer 官网地址: http://www.whitsoftdev.com/trayconizer/ 下载地址: http://www.whitsoftdev.com/fil ...

  3. C#实现winform软件开机自动启动并最小化到系统托盘

    一.开机自动启动: 拖一个CheckBox 1.软件启动时给CheckBox重置状态: RegistryKey R_local = Registry.LocalMachine;             ...

  4. Delphi 7下最小化到系统托盘

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 在Del ...

  5. MFC中将窗口最小化到系统托盘和还原

    通过以下步骤可以在MFC程序中将窗口最小化到系统托盘,和还原成窗口,附加代码中如有特殊说明则会用红色标出. 1.添加一个ICON图标,其ID为IDI_ICON_TESTICON,在VS2008坐标的R ...

  6. MFC:怎么将程序窗口最小化到系统托盘

    (一)原理 1.最小化的原理:首先要将窗口隐藏,然后在右下角绘制图标. 2.恢复的原理:将窗口显示,再将托盘中的图片删除. (二)程序实现 1.自定义消息WM_SHOWTASK: #define WM ...

  7. VC实现将对话框最小化到系统托盘

    1.minisysDlg.h头文件设置: 1)public: void setTray();//设置托盘    NOTIFYICONDATA nid;//NOTIFYICONDATA结构包含了系统用来 ...

  8. C#实现窗口最小化到系统托盘

    关键字:C# 最小化 托盘 原文:http://www.cnblogs.com/txw1958/archive/2012/12/17/csharp-minimize-tray.html 先添加noti ...

  9. C# WinForm窗口最小化到系统托盘

    1.设置WinForm窗体属性showinTask=false  2.加notifyicon控件notifyIcon1,为控件notifyIcon1的属性Icon添加一个icon图标.  3.添加窗体 ...

最新文章

  1. 支付宝支付 第三集:搭建项目及测试(含代码)
  2. CentOS 5 下yum安装 Mono 2.4
  3. python知识:NetworkX初步
  4. 多个服务器数据互通_5月23日部分服务器数据互通公告!
  5. linux 查看共享磁盘_如何可视化地查看 Linux 系统磁盘使用情况?
  6. c++ 文件读写(转)
  7. naked 函数调用
  8. java获取文本文件的编码格式
  9. 【计算机网络】南航计算机网络第一章 概述
  10. 工具 IDA Pro
  11. Photoshop插件-HDR(四)-脚本开发-PS插件
  12. canvas mdn_MDN文档 canvas教程笔记
  13. JS toFixed(2) 返回 -0.00
  14. TCP通信 、 UDP通信
  15. html列表太多转为下滑菜单,利用CSS过渡属性Transition制作缓缓弹出的纯CSS下拉菜单...
  16. JavaScript中split()方法详解
  17. 水冒泡了几度_水开了为什么会冒泡?
  18. 寒假社会实践完整版内容,一套流程
  19. ubuntu16.04 rtl8821ce无线网卡wifi频繁掉线问题解决
  20. 主题 支持 php 7.2,最新七星修改二开正米酷影视7.2完整版/支持自定义解析/支持PHP7.0及以上...

热门文章

  1. learnopencv 之 Delaunay 显示动态绘制obama脸型特征 @ Jupyter
  2. 网站上的学习——Java基础的复盘
  3. 平年、闰年的判断(python简单地表达)
  4. listview下拉刷新上拉加载扩展(二)-仿美团外卖
  5. 某智能手表SIM卡不识别问题分析
  6. 功能上新|使用 Excel 低门槛进行指标分析!
  7. 音视频开发一:音视频基础概念
  8. 体验Impress.js
  9. python dict items iteritems_python字典中的items和iteritems
  10. mesonbuild wrap