3

I want to set a particular portion(like only a frame or widget) of my application window to taskbar thumbnail.I found one windows API that is ITaskbarList3::SetThumbnailClip here but this is in C++.I want to do this in python.However PyQt5 contains one class that is Qt Windows Extras which doesnot include this function.I have also found something that show one example here.This link might help you to solve easily. As I am a beginner ,i dont know how to do that properly.

Edit And Fix Me:-

I have tried the second link provided in the question,I have installed comptypes Module through PIP and i have copied taskbarlib.tlb file from github as i have not Windos SDK installed to generate this file as said in the answer here.

Here is my code.

from PyQt5.QtWidgets import *
import sys
##########----IMPORTING Comtypes module
import comtypes.client as cc
cc.GetModule('taskbarlib.tlb')
import comtypes.gen.TaskbarLib as tb
taskbar=cc.CreateObject('{56FDF344-FD6D-11d0-958A-006097C9A090}',interface=tb.ITaskbarList3)
##################
class MainUiClass(QMainWindow):
     def __init__(self,parent=None):
        super(MainUiClass,self).__init__(parent)
        self.resize(600,400)
        self.frame=QFrame(self)
        self.frame.setGeometry(100,100,400,200)
        self.frame.setStyleSheet('background:blue')
if __name__=='__main__':
      app=QApplication(sys.argv)
      GUI=MainUiClass()
      GUI.show()
      taskbar.HrInit()
      ####--This is just to check its working or not by setting a tasbar progress bar value
      taskbar.SetProgressValue(GUI.winId(),40,100)
      ##########################################
      ##########This is a method to get the LP_RECT instace as per Microsoft API doc.Using Ctypes and got ctypes.wintypes.RECT object  
      from ctypes import POINTER, WINFUNCTYPE, windll, WinError
      from ctypes.wintypes import BOOL, HWND, RECT
      prototype = WINFUNCTYPE(BOOL, HWND, POINTER(RECT))
      paramflags = (1, "hwnd"), (2, "lprect")
      GetWindowRect = prototype(("GetWindowRect", windll.user32), paramflags)
      newrect=GetWindowRect(int(GUI.frame.winId()))
      print(newrect)
      taskbar.SetThumbnailClip(int(GUI.winId()),newrect)
      sys.exit(app.exec_())

i have got that method to find LP_RECT instance form Ctypes module Doc. hereenter image description here But I have a problem I want to set the frame(blue colored) into taskbar and i got thisenter image description here

Look at the screenshot,the taskbarprogress value that i have set for testing, works fine ,but the thumbnail part is just Unexpected. Can anyone help me to fix this?

Rajkumar
  • 530
  • 4
  • 9
  • [ITaskbarList3::SetThumbnailClip](https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-itaskbarlist3-setthumbnailclip) isn't really C++. It's rather C. Not that it matters a whole lot, since `ITaskbarList` is a COM interface, and language agnostic. Try to find a Python module that handles COM for you. Maybe [pywin32](https://pypi.org/project/pywin32/) does, you'd have to see for yourself. – IInspectable Dec 04 '20 at 15:33
  • 1
    check this link [here](https://stackoverflow.com/questions/1736394/using-windows-7-taskbar-features-in-pyqt/1744503#1744503).You might solve this easily.I dont know how to do that because those modules are very lengthy and hard to understand for a beginner like me. @llnspectable – Rajkumar Dec 04 '20 at 15:36
  • The QWinThumbnailToolBar() class seems pretty straight forward, you just have to set the pixmap using [`setIconicThumbnailPixmap()`](https://doc.qt.io/qt-5/qwinthumbnailtoolbar.html#iconicThumbnailPixmap-prop). – musicamante Dec 04 '20 at 19:22
  • That is just a time wasting.cause it only set an image to thumbnail not the real working thumbnail?Bdw look at https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-itaskbarlist3-setthumbnailclip , do you know how to find *Rect I mean LP_Rect of a widget in python. @musicamante – Rajkumar Dec 04 '20 at 19:33
  • That is *not* a "time wasting". You have to create the pixmap of the portion of the window you're interested into, which usually is achieved using [`render()`](https://doc.qt.io/qt-5/qwidget.html#render). – musicamante Dec 04 '20 at 19:50
  • @musicamante,I fixed this please check and close this issue. – Rajkumar Dec 05 '20 at 17:54
  • 3
    @Rajkumar 1. Yours is not an issue, but a question. 2. If you found an answer, **do not edit the question**, provide your own *answer*, do not put "Resolved, please close", etc. You've been here on SO for some time now, you should already know that this place is not just *for you*: questions and answers are for everybody. 3. Why should we "close" it? What if somebody else has a similar problem? 4. Please do not add screenshots from somewhere elase to "explain" the solution, it's absolutely meaningless, it's very annoying and difficult to read, and doesn't really help your post. – musicamante Dec 05 '20 at 19:05
  • 2
    I have rolled back your edit. The answer never belongs in the question. Instead, you should post a proper answer to your question below. For more information, see: [Can I answer my own question?](https://stackoverflow.com/help/self-answer) – Cody Gray - on strike Dec 06 '20 at 12:01
  • hi @musicamante,It is completely out of my mind that i can aswer my posts by myself.AnywayI have answered the question,Is it OK? Yesterday I didnot meant "close" means to delete the post,if i meant that then i would have deleted it by myself why would i request to moderators??.what i meant is that the status of this post should be close so that it requires no answer from now as it is fixed.So Dont get me wrong.Yesterday i posted that screenshot as i have no times to write those codes and explanation. – Rajkumar Dec 06 '20 at 14:17
  • Please see [Can I answer my own question?](https://stackoverflow.com/help/self-answer) (tl;dr: yes, and you are actually *encouraged* to do so). – desertnaut Dec 06 '20 at 15:07
  • @Rajkumar Questions are closed only when they are considered invalid (duplicate, not focused, not clear, or asks for "how-to", suggestions, etc), otherwise they are *always* open to answers. The fact that you found a solution is irrelevant to this: remember that StackOverflow is a Q&A website aimed to be a repository of *knowledge*, meaning that its posts should always be useful to others, not only to those who ask for help. While you found an answer, that doesn't mean that somebody else couldn't have *another* answer (an alternate solution, or even a *better* solution). Finally, SO is *not*-> – musicamante Dec 06 '20 at 15:08
  • Yes, that is also a point @musicamante.I will remember this nexttime.Is my explanation for the answer is OK or I need to modify it? – Rajkumar Dec 06 '20 at 15:11
  • -> a place for answers given in a rush. While answers can be given in a matter of minutes, they should also be *good* answers (as much as questions should always be *good* questions) both in contents *and* writing. If you don't have time to write a more complete answer, nobody is pushing you. Take your time, do it when you can. Sometimes it takes a lot of time to write good questions and the same goes even for answers (I personally wrote answers that took me more hours), but it's always worth it: for you as the one asking, and as the one looking for help for a similar problem. – musicamante Dec 06 '20 at 15:11
  • Thanks,for the advice,i will keep in mind..@musicamante – Rajkumar Dec 06 '20 at 15:13

1 Answers1

1

Thanks to Eliya Duskwight to help me slove this. I have corrected my code.

This is For PyQt5 And PySide2 as well as Tkinter

Here is mycode for PyQt5/PySide2

from PyQt5.QtWidgets import *          ###For PyQt5
from PySide2.QtWidgets import *        ###For PySide2
import sys
###Most Important Part###
import comtypes.client as cc
cc.GetModule('taskbarlib.tlb')
import comtypes.gen.TaskbarLib as tb
taskbar=cc.CreateObject('{56FDF344-FD6D-11d0-958A-006097C9A090}',interface=tb.ITaskbarList3)
class MainUiClass(QMainWindow):
   def __init__(self,parent=None):
        super(MainUiClass,self).__init__(parent)
        self.resize(600,400)
        self.setStyleSheet('background:red')
        self.frame=QFrame(self)
        self.frame.setGeometry(100,100,400,200)
        self.frame.setStyleSheet('background:blue')
if __name__=='__main__':
      app=QApplication(sys.argv)
      GUI=MainUiClass()
      GUI.show()
      taskbar.HrInit()
      ##You need to find "hwnd" of your Window and "LP_RECT" instance of Geometry you want, as per Microsoft API Doc. using Ctypes
      from ctypes.wintypes import  RECT,PRECT 
      newrect=PRECT(RECT(0,0,600,400))
      taskbar.SetThumbnailClip(int(GUI.winId()),PRECT(RECT(0,0,600,400)))

Not only you can use this API for thumbnailclip but also for various functions like ThumbnailToolTip,Taskbar Progress,Taskbar Progressbar,Taskbar Overlay Icon,Adding Buttons etc.You need to read the interface here

>>> For Tkinter

from tkinter import *
from ctypes import windll
from ctypes.wintypes import  RECT,PRECT
###Most Important Part###
import comtypes.client as cc
cc.GetModule('taskbarlib.tlb')
import comtypes.gen.TaskbarLib as tb
taskbar=cc.CreateObject('{56FDF344-FD6D-11d0-958A-006097C9A090}',interface=tb.ITaskbarList3)
root=Tk()
root.geometry("400x300")
root.config(bg="red")
frame=Frame(root,bg='blue',width=200,height=100)
frame.place(x=100,y=100)

def setThumbnail():
   hwnd = windll.user32.GetParent(root.winfo_id())
   print(hwnd)
   taskbar.HrInit()
   taskbar.SetThumbnailClip(hwnd,PRECT(RECT(0,0,60,60)))#Geometry You Want To Set
root.after(1000,setThumbnail)   
root.mainloop()

I found root.winfo_id() doesnot give the correct hwnd.I dont know why?So i used hwnd = windll.user32.GetParent(root.winfo_id()) to find the correct one.

Note: This works after the window is visible,So for PyQt5/PySide2,it should be called after calling window.show() & For Tkinter,it should be called after sometime,for that you can use root.after() Or Some event, and You should have that taskbarlib.tlb file pasted in your module folder or in your script folder.You can also generate it using Windows SDK or IDL compiler.Then install comtypes module to work.And remember

The return of S_OK ,means the return of SetThumbnailClip() is 0 always.so anything except 0 is a error.This might crash the application.And As per Microsoft API,the Minimum Required OS is Windows7.

Rajkumar
  • 530
  • 4
  • 9