PyQt5/Tkinter Fenster hinter Windows Desktop Icons verschieben?

1 Antwort

Vom Fragesteller als hilfreich ausgezeichnet

Du müsstest erst das Desktopfenster finden und davon das Subfenster (bzw. dessen Handle), auf dem der Hintergrund gezeichnet wird.

Initial ist Progman der relevante Kindknoten, der den gesamten Desktopbereich (den Shell-Desktop) darstellt. Unter ihm liegt SHELLDLL_DefView mit einem SysListView32 Control, welches für das Zeichnen der Desktopicons zuständig ist. Allerdings kann sich die Hierachie ändern (bspw. beim Drücken von ALT + Tab) und die erwähnten Kindknoten werden von Progman separiert.

Wenn man sich Lösungen bestehender C++-Anwendungen anschaut (oder Blogartikel wie den von G. Degeneve oder den auf programming.vip liest), behilft man sich öfter damit, ein neues Fenster zu erzeugen, welches unter den Desktopicons liegt. Dies kann angetriggert werden, indem eine entsprechende Nachricht an Progman verschickt wird:

HWND progman = FindWindow(L"Progman", NULL);
SendMessageTimeout(progman, 0x052C, 0, 0, SMTO_NORMAL, 1000, nullptr);

Beachte, dass es sich hierbei nicht um von Microsoft dokumentierte Methodiken handelt. Manipulationen sind also eigentlich nicht vorgesehen und es ist auch nicht sicher, wie lange man auf diesem Weg zu einem Ziel kommt.

Sobald das Fenster jedenfalls angelegt wurde, wird es im Baum gesucht. Es sollte der nachfolgende Nachbar des Fensters sein, welches SHELLDLL_DefView beinhaltet.

WorkerW
  SHELLDLL_DefView
    SysListView32
WorkerW (= neues Fenster)
Progman

Soweit zur Theorie.

Für eine Lösung in Python benötigst du erst einmal eine Schnittstelle zur Windows API. Man könnte win32gui verwenden oder ctypes.

Beispiel:

root = win32gui.GetDesktopWindow()

# or
root = ctypes.windll.user32.GetDesktopWindow()

Mittels der FindWindowEx- / FindWindowExW-Funktion kannst du nach den jeweiligen Knoten / Fenstern suchen.

In PyQt bräuchtest du folgend ein natives Widget, an welches du deine Elemente hängen kannst.

Beispiel:

nativeWindow = QWindow.fromWinId(handle);

widget = QWidget()
widget.windowHandle().setParent(nativeWindow);

Beachte in diesem Kontext die Anmerkung aus der Qt-Dokumentation:

Note: The resulting  QWindow should not be used to manipulate the underlying native window (besides re-parenting), or to observe state changes of the native window. Any support for these kind of operations is incidental, highly platform dependent and untested.

Quelle

Berücksichtige diese Information am besten unabhängig davon, mit welchem GUI-Framework du arbeitest. Vermeide besser auch Aktionen, die eine Nutzereingabe fordern (bspw. Modals).

Noch ein anderes GUI-Toolkit, welches man verwenden könnte, wäre wxPython:

class Window(wx.Frame):
  def __init__(self, handle):
    # initialization ...
    self.AssociateHandle(handle)
    self.draw()

  def draw(self):
    device_context = wx.WindowDC(self)
    # draw something ...
    device_context.Destroy()
iNeedHelp961 
Fragesteller
 03.04.2022, 19:13

Hab es mit Python und WebView dann noch geschafft. Aber ich danke dir! Jeder andere wird dank der Antwort nicht erst 2 Wochen Verzweifeln müssen xD.

0