首页 > 编程语言 >SysTrayIcon 改的 python tkinter 最小化至系统托盘,适用TTK

SysTrayIcon 改的 python tkinter 最小化至系统托盘,适用TTK

时间:2024-03-27 11:26:43浏览次数:34  
标签:tkinter option python menu 系统托盘 win32gui win32con 图标 icon

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

1.点击最小化隐藏至托盘
点击最小化
2.托盘图标右键菜单展示,左键返回Tk界面。
托盘图标
托盘图标可以自定义,修改了SysTrayIcon更容易调用,Demo窗口加了注释,具体查看 _Main 类。

 

代码如下:

  import win32api, win32con, win32gui_struct, win32gui
  import os, tkinter as tk
   
  class SysTrayIcon (object):
  '''SysTrayIcon类用于显示任务栏图标'''
  QUIT = 'QUIT'
  SPECIAL_ACTIONS = [QUIT]
  FIRST_ID = 5320
  def __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 = icon
  s.hover_text = hover_text
  s.on_quit = on_quit
  s.root = tk_window
   
  menu_options = menu_options + (('退出', None, s.QUIT),)
  s._next_action_id = s.FIRST_ID
  s.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_id
   
  s.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_name
  wc.style = win32con.CS_VREDRAW | win32con.CS_HREDRAW;
  wc.hCursor = win32gui.LoadCursor(0, win32con.IDC_ARROW)
  wc.hbrBackground = win32con.COLOR_WINDOW
  wc.lpfnWndProc = message_map #也可以指定wndproc.
  s.classAtom = win32gui.RegisterClass(wc)
   
  def activation(s):
  '''激活任务栏图标,不用每次都重新创建新的托盘图标'''
  hinst = win32gui.GetModuleHandle(None)# 创建窗口。
  style = win32con.WS_OVERLAPPED | win32con.WS_SYSMENU
  s.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 = None
  s.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_DEFAULTSIZE
  hicon = 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_MODIFY
  else: message = win32gui.NIM_ADD
   
  s.notify_id = (s.hwnd, 0, # 句柄、托盘图标ID
  win32gui.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_option
  if 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 += 1
  return result
   
  def 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:# 双击左键
  pass
  elif 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 hbm
   
  def 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()
   

 

2024-03-27 11:07:15【出处】:https://www.cnblogs.com/ddgo/p/17994150

=======================================================================================

标签:tkinter,option,python,menu,系统托盘,win32gui,win32con,图标,icon
From: https://www.cnblogs.com/mq0036/p/18098509

相关文章

  • Python pandas模块
    1、转换python字典类型为dataframe#!/usr/bin/envpython#-*-coding:utf-8-*-#__author__=#pandas>=1.5.3importpandasaspdpydict={'Dosage':'1.1.1.1,2.2.2.2,4.4.4.4,5.5.5.5','HalfLife':'6.6.6.6,7.7.7.7,8.8.8.......
  • 如何系统得自学python?——11.文件操作
    一、文件操作的作用 ⽂件操作包含:打开、关闭、读、写、复制......⽂件操作的的作⽤是:读取内容、写⼊内容、备份内容......⽂件操作的作⽤就是把⼀些内容(数据)存储存放起来,可以让程序下⼀次执⾏的时候直接使⽤,⽽不必重新制作⼀份,省时省⼒。 二、文件操作方式1.文件操作......
  • Python程序打包成exe、隐藏运行窗口
    Python隐藏运行窗口的实现方法1.流程图st=>start:开始op1=>operation:创建Python脚本op2=>operation:添加代码op3=>operation:保存脚本op4=>operation:编译脚本op5=>operation:生成可执行文件op6=>operation:隐藏运行窗口e=>end:完成st->op1->op2->op3->op4......
  • 没有Python基础,如何学习用Python写机器学习
    前言我是一个完全没用过python的人,所以,想写机器学习,就得从语法入手。首先上W3cSchool去学习基础语法。基础语法都差不多,重点看一下函数,模块,面向对象。函数的写法稍有不同,格式上类似yml的写法;模块会介绍import的相关信息;面向对象会介绍类的相关信息。参考网站:https://www.w3c......
  • Python接口自动化测试的学习笔记9——logging日志
    1、引言在进行Python接口自动化测试时,日志记录是一项至关重要的任务,它可以帮助开发者追踪测试过程中的详细信息,包括请求与响应数据、错误消息、调试信息等,从而有效地定位问题并提高测试效率。下面,我们将探讨如何在Python接口自动化测试项目中构建和配置一个强大的日志记录系统......
  • python的应用 | 提取指定文件夹下所有PDF文件的页数
    需求背景:由于要打印几十页pdf,跟打印店对接的时候,为了防止被坑,提前了解一下,所有文档一共有多少页,于是想到了用python来提取pdf文件的页数完整代码:importosfromPyPDF2importPdfReaderdefget_pdf_page_count(folder_path):#初始化总页数变量total_pages=0......
  • Python-VBA编程500例-020-02(入门级)
    第k个组合(ThekthCombination)的问题在实际应用中具有广泛的用途,它涉及从n个不同元素中选出k个元素的所有可能组合。这种组合的概念在许多领域都有重要的应用,常见的一些具体应用有:1、彩票与赌博:在某些彩票或赌博游戏中,参与者需要选择特定数量的号码或符号。这些号码或符号的......
  • [Python]细节与使用经验
    【版权声明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权)https://www.cnblogs.com/cnb-yuchen/p/18031983出自【进步*于辰的博客】纯文字阐述,内容比较干。并且,由于考虑到时间长了恐有所遗漏,便即兴记录,并没有对内容进行筛选、排序。因此,大家在阅读时可以直接Ctrl+F进行......
  • 肖sir__python之模块7.1
    ython之模块一、模块的介绍(1)python模块,是一个python文件,以一个.py文件,包含了python对象定义和pyhton语句(2)python对象定义和python语句(3)模块让你能够有逻辑地组织你的python代码段。(4)把相关的代码分配到一个模块里能让你的代码更好用,更易懂(5)模块能定义函数,类和变量,模块里也能包含可......
  • python 常用包
    python对于从git下载的内容,进入包内使用以下命令: pythonsetup.pybuildinstall 对于whl包,可省去后面的whl直接安装,假如有whl包是test123.whlpipinstalltest123 pip: 是Python包管理工具,python的其它包安装一般都是通过pip操作。python3.4+自带有此包。下载......