该功能是各大编译器或者一些软件在执行耗时操作时,显示进度的一种方式:
Qt
如果是使用的pyQt或者是Qt就很简单了,直接使用QWinTaskbarProgress就可以完成该功能。
Wxpython
但是wxpython就没有那么简单了,需要了解一些window的特性。
预备知识
这里需要简单了解COM在Window上的概念,Window的构件框架,可以将一些功能模块化,能够兼容的使用其中提供的功能,只暴露出接口Class提供给我们使用。
这里CLSID就是每一个接口Class的全局ID,例如CLSID_TaskbarList的为{56FDF344-FD6D-11d0-958A-006097C9A090}。
然后采用组合或者继承的方式,可以从CLSID的类中选择实例化接口:
例如:
pythoncom.CoCreateInstance(shell.CLSID_TaskbarList, None, pythoncom.CLSCTX_INPROC_SERVER, shell.IID_ITaskbarList)
这里的None与CLSID采用的继承或者组合的方式有关,一般情况下是None.
而pythoncom.CLSCTX_INPROC_SERVER则与注册该功能是否存在InProcServer32有关:
这样大概就知道了实现window任务栏进度条的方法,需要从微软提供的官方COM中使用其中的接口进行实现功能。
方式一
这里我首先尝试使用的是win32com的,但是目前的该功能仅仅支持ItaskbarList的基础类,功能也仅仅是支持有限的几个,删除激活任务栏而已。
大概的流程是:
import time
import win32api
import win32con
import win32gui
import pythoncom
from win32com.shell import shell, shellcon
# 获取 Shell 的 COM 接口
shell_instance = pythoncom.CoCreateInstance(shell.CLSID_TaskbarList, None, pythoncom.CLSCTX_INPROC_SERVER, shell.IID_ITaskbarList)
shell_instance.HrInit()
shell_instance.AddTab(hwnd)
shell_instance.ActivateTab(hwnd)
shell_instance.DeleteTab(hwnd)
这种方式最后宣告失败,就算是我从window中寻找到了对应的IID_ITaskbarList3为{EA1AFB91-9E28-4B86-90E9-9E9F8A5EEFAF},并做了修改,可在shell.CLSID_TaskbarList寻找不到这个子接口,一直报错。
方式二:
直接使用python调用COM的常规方法。
参考:nullhttps://www.coder.work/article/347057
参考:Using API's in a:: format? - Programming (C#, C++, JAVA, VB, .NET etc.) - Neowinhttps://www.neowin.net/forum/topic/716968-using-apis-in-a-objectaction-format/#comment-590434472
参考微软ITaskbarList3文档:
ITaskbarList3 (shobjidl_core.h) - Win32 apps | Microsoft Learnhttps://learn.microsoft.com/zh-cn/windows/win32/api/shobjidl_core/nn-shobjidl_core-itaskbarlist3
主代码如下:
# coding:utf-8
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# {EA1AFB91-9E28-4B86-90E9-9E9F8A5EEFAF} IID_ITaskbarList3
import wx
import comtypes.client as cc
cc.GetModule("TaskbarLib.tlb")
import comtypes.gen.TaskbarLib as tbl
class MyFrame(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, size=(300, 200))
self.panel = wx.Panel(self)
self.progress = 0
self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)
self.timer.Start(1000)
def OnTimer(self, event):
self.progress += 10
if self.progress > 100:
self.progress = 0
self.SetTaskbarProgress(self.progress)
def SetTaskbarProgress(self, progress):
hwnd = self.GetHandle()
taskbar = cc.CreateObject(
"{56FDF344-FD6D-11d0-958A-006097C9A090}",
interface=tbl.ITaskbarList3)
taskbar.HrInit()
taskbar.AddTab(hwnd)
taskbar.ActivateTab(hwnd)
"""
TBPF_NOPROGRESS (0x00000000)
停止显示进度并将按钮返回到其正常状态。 使用此标志调用此方法,以在操作完成或取消时关闭进度栏。
TBPF_INDETERMINATE (0x00000001)
进度指示器的大小不会增加,但会重复沿任务栏按钮的长度循环。 这表示活动未指定完成进度的比例。 正在取得进展,但无法预测操作需要多长时间。
TBPF_NORMAL (0x00000002)
进度指示器的大小从左到右增长,与估计完成的操作量成比例。 这是一个确定的进度指示器:正在对操作持续时间进行预测。
TBPF_ERROR (0x00000004)
进度指示器变为红色,表示在其中一个正在广播进度的窗口中发生了错误。 这是一个确定的状态。 如果进度指示器处于不确定状态,则会切换到红色确定性显示,其中泛型百分比不指示实际进度。
TBPF_PAUSED (0x00000008)
进度指示器变为黄色,表示进度当前在其中一个窗口中已停止,但用户可以恢复。 不存在错误条件,并且没有任何内容阻止进度继续。 这是一个确定的状态。 如果进度指示器处于不确定状态,则会切换到黄色确定性显示,其中泛型百分比不指示实际进度。
"""
taskbar.SetProgressState(hwnd, 0x00000001)# TBPF_INDETERMINATE (0x00000001)
taskbar.SetProgressValue(hwnd, progress, 100)
app = wx.App(False)
frame = MyFrame(None, wx.ID_ANY, "Taskbar Progress Indicator")
frame.Show()
app.MainLoop()
可以看到使用的是comtypes模块来进行实现了该功能,这里可能会有一个疑惑:
TaskbarLib.tlb是什么?
简单理解就是类似与一个C语言的.h文件,能够从中获取对应的接口来进行使用,而这里文件的生成就是使用微软提供的工具。
TaskbarLib.tlb的生成
这里该文件是由一个配置文件TaskbarLib.idl:
[
uuid(683BF642-E9CA-4124-BE43-67065B2FA653),
version(1.0),
]
library TaskbarLib
{
[
uuid(56FDF342-FD6D-11d0-958A-006097C9A090),
object,
]
interface ITaskbarList : IUnknown
{
HRESULT _stdcall HrInit();
HRESULT _stdcall AddTab([in] long hwnd);
HRESULT _stdcall DeleteTab([in] long hwnd);
HRESULT _stdcall ActivateTab([in] long hwnd);
HRESULT _stdcall SetActivateAlt([in] long hwnd);
};
[
uuid(602D4995-B13A-429b-A66E-1935E44F4317),
object,
]
interface ITaskbarList2 : ITaskbarList
{
HRESULT MarkFullscreenWindow(
[in] long hwnd,
[in] BOOL fFullscreen);
}
cpp_quote("#ifdef MIDL_PASS")
typedef IUnknown* HIMAGELIST;
typedef IUNknown* HICON;
cpp_quote("#endif")
cpp_quote("#include <pshpack8.h>")
typedef struct tagTHUMBBUTTON
{
DWORD dwMask;
UINT iId;
UINT iBitmap;
HICON hIcon;
WCHAR szTip[260];
DWORD dwFlags;
} THUMBBUTTON, *LPTHUMBBUTTON;
cpp_quote("#include <poppack.h>")
[
uuid(ea1afb91-9e28-4b86-90e9-9e9f8a5eefaf),
object,
]
interface ITaskbarList3 : ITaskbarList2
{
// Flags for Setting Taskbar Progress state
typedef [v1_enum] enum TBPFLAG
{
TBPF_NOPROGRESS = 0x00000000,
TBPF_INDETERMINATE = 0x00000001,
TBPF_NORMAL = 0x00000002,
TBPF_ERROR = 0x00000004,
TBPF_PAUSED = 0x00000008,
} TBPFLAG;
cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(TBPFLAG)")
// Flags for SetTabActive
typedef [v1_enum] enum TBATFLAG
{
TBATF_USEMDITHUMBNAIL = 0x00000001,
TBATF_USEMDILIVEPREVIEW = 0x00000002,
} TBATFLAG;
cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(TBATFLAG)")
HRESULT SetProgressValue(
[in] long hwnd,
[in] ULONGLONG ullCompleted,
[in] ULONGLONG ullTotal);
HRESULT SetProgressState(
[in] long hwnd,
[in] TBPFLAG tbpFlags);
HRESULT RegisterTab(
[in] long hwndTab,
[in] HWND hwndMDI);
HRESULT UnregisterTab(
[in] long hwndTab);
HRESULT SetTabOrder(
[in] long hwndTab,
[in] long hwndInsertBefore);
HRESULT SetTabActive(
[in] long hwndTab,
[in] long hwndMDI,
[in] TBATFLAG tbatFlags);
HRESULT ThumbBarAddButtons(
[in] long hwnd,
[in] UINT cButtons,
[in, size_is(cButtons)] LPTHUMBBUTTON pButton);
HRESULT ThumbBarUpdateButtons(
[in] long hwnd,
[in] UINT cButtons,
[in, size_is(cButtons)] LPTHUMBBUTTON pButton);
HRESULT ThumbBarSetImageList(
[in] long hwnd,
[in] HIMAGELIST himl);
HRESULT SetOverlayIcon(
[in] long hwnd,
[in] HICON hIcon,
[in, string] LPCWSTR pszDescription);
HRESULT SetThumbnailTooltip(
[in] long hwnd,
[in, string] LPCWSTR pszTip);
HRESULT SetThumbnailClip(
[in] long hwnd,
[in] RECT *prcClip);
}
[ uuid(56FDF344-FD6D-11d0-958A-006097C9A090) ] coclass TaskbarList { interface ITaskbarList3; }
};
这里的midl编译器比较麻烦获得,如果电脑有安装VSStudio可能会简单很多:
打开工具-命令行-开发者(powershell),在这里输入midl即可。
使用MIDL编译器进行生成:
midl /tlb .\TaskbarLib.tlb TaskBarLib.idl
生成dll:
TlbImp .\TaskbarLib.tlb /out:TaskbarLib.dll
这里提供一个编译好的备份:
链接:https://pan.baidu.com/s/1-0UQrzjC0d_paDP5w5KknQ
提取码:947z