如何用python移动桌面图标?

问题描述 投票:0回答:1

我正在制作一个Python程序,使用

LVM_SETITEMPOSITION
winapi
移动桌面图标,但我对
commctrl.LVM_SETITEMPOSITION
有问题,它给了我一个错误
'int' object is not callable
。这是我的代码:

import win32gui
import commctrl
from time import sleep
from ctypes import wintypes

hd = wintypes.HWND

hd = win32gui.FindWindow("Progman", None)
hd = win32gui.FindWindowEx(hd, 0, "SHELLDLL_DefView", None)
hd = win32gui.FindWindowEx(hd, 0, "SysListView32", None)

i = 0
while i < 1000:
  commctrl.LVM_SETITEMPOSITION(hd, 0, i, i)
  i+100
  sleep(1)
python winapi
1个回答
-1
投票

正确的方法(使用COM)比我采取的捷径(仍在答案的末尾)更痛苦。

资源:

我从第 1st URL 开始“翻译”代码。一切都很顺利,获得了 IFolderView,它没有被 PyWin32COM 扩展包裹。我尝试通过 [SO]:在 Python 中实现 COM 接口(@SimonMourier 的答案)来解决这个问题,但没有成功。

所以,我只能选择自己添加 IFolderView(部分)支持。 PR[GitHub]:mhammond/pywin32 - IFolderView COM 客户端合并到240220上的main)。

在本地构建shell.pyd(包含上述更改)后,我能够使用以下脚本获得相同的行为(工作正常)。

code01.py

#!/usr/bin/env python

import msvcrt
import sys
import time

import pythoncom
import win32com.client as wcomcli
from win32com.shell import shell, shellcon


SWC_DESKTOP = 0x08
SWFO_NEEDDISPATCH = 0x01

IID_IFolderView = "{CDE725B0-CCC9-4519-917E-325D72FAB4CE}"
IID_IShellView = "{000214E3-0000-0000-C000-000000000046}"


def main(*argv):
    CLSID_ShellWindows = "{9BA05972-F6A8-11CF-A442-00A0C90A8F39}"
    shell_windows = wcomcli.Dispatch(CLSID_ShellWindows)
    hwnd = 0
    dispatch = shell_windows.FindWindowSW(
        wcomcli.VARIANT(pythoncom.VT_I4, shellcon.CSIDL_DESKTOP),
        wcomcli.VARIANT(pythoncom.VT_EMPTY, None),
        SWC_DESKTOP, hwnd, SWFO_NEEDDISPATCH,
    )
    service_provider = dispatch._oleobj_.QueryInterface(pythoncom.IID_IServiceProvider)
    browser = service_provider.QueryService(shell.SID_STopLevelBrowser, shell.IID_IShellBrowser)
    shell_view = browser.QueryActiveShellView()
    print(shell_view.GetCurrentInfo())
    folder_view = shell_view.QueryInterface(IID_IFolderView)
    #print(folder_view.QueryInterface(shell.IID_IShellView))
    items_len = folder_view.ItemCount(shellcon.SVGIO_ALLVIEW)
    print(f"ItemCount: {items_len}")
    for i in range(items_len):
        item = folder_view.Item(i)
        print(f"Item {i:2d}\n  {item}")

    print(f"Spacings: {folder_view.GetSpacing(300, 300)}, {folder_view.GetDefaultSpacing()}")

    item = b"\x1fx@\xf0_d\x81P\x1b\x10\x9f\x08\x00\xaa\x00/\x95N"  # "Recycle Bin" equivalent (in my case)
    #item = 0  # May also be the index (still "Recicle Bin" equivalent)
    #item = 1

    print(f"Item {item} position: {folder_view.GetItemPosition(item)}")
    for i in range(0, 1080, 16):
        print(i)
        folder_view.SelectAndPositionItem(item, (i, i), shellcon.SVSI_POSITIONITEM)
        time.sleep(0.5)
        if msvcrt.kbhit():
            break


if __name__ == "__main__":
    print(
        "Python {:s} {:03d}bit on {:s}\n".format(
            " ".join(elem.strip() for elem in sys.version.split("\n")),
            64 if sys.maxsize > 0x100000000 else 32,
            sys.platform,
        )
    )
    rc = main(*sys.argv[1:])
    print("\nDone.\n")
    sys.exit(rc)

输出

[cfati@CFATI-W10PC064:e:\Work\Dev\StackExchange\StackOverflow\q071905594]> "c:\Work\Dev\VEnvs\py_pc064_03.10_test0\Scripts\python.exe" ./code01.py
Python 3.10.11 (tags/v3.10.11:7d4cc5a, Apr  5 2023, 00:38:17) [MSC v.1929 64 bit (AMD64)] 064bit on win32

(1, 1075839524)
ItemCount: 8
Item  0
  b'\x1fx@\xf0_d\x81P\x1b\x10\x9f\x08\x00\xaa\x00/\x95N'
Item  1
  b':\x00\r\x08\x00\x00NX\x95\xa4 \x00ADOBEA~2.LNK\x00\x00T\x00\t\x00\x04\x00\xef\xbemV\xa2\xbcRX\xe1h.\x00\x00\x00\xd8\x96\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00k\xc7(\x00A\x00d\x00o\x00b\x00e\x00 \x00A\x00c\x00r\x00o\x00b\x00a\x00t\x00.\x00l\x00n\x00k\x00\x00\x00\x1c\x00'
Item  2
  b':\x00\xae\x00\x00\x00\x87O\x96I&\x00desktop.ini\x00H\x00\t\x00\x04\x00\xef\xbe\x87O\xdcITX.m.\x00\x00\x00{\xb2\x03\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x86)\xbf\x00d\x00e\x00s\x00k\x00t\x00o\x00p\x00.\x00i\x00n\x00i\x00\x00\x00\x1a\x00'
Item  3
  b':\x00\xe4\x08\x00\x00TXtm \x00MICROS~1.LNK\x00\x00V\x00\t\x00\x04\x00\xef\xbesQ\xd1=TXtm.\x00\x00\x00s\xb8\x04\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\xf0Q\x00M\x00i\x00c\x00r\x00o\x00s\x00o\x00f\x00t\x00 \x00E\x00d\x00g\x00e\x00.\x00l\x00n\x00k\x00\x00\x00\x1c\x00'
Item  4
  b'2\x00\x19\x04\x00\x00wSiN \x00CONNEC~1.LNK\x00\x00\x86\x00\t\x00\x04\x00\xef\xbewSiNRX\xe1h.\x00\x00\x00\xa7\x8d\x00\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X\xe5>\x00C\x00o\x00n\x00n\x00e\x00c\x00t\x00i\x00o\x00n\x00 \x00t\x00o\x00 \x00Q\x00C\x00_\x00A\x00I\x00C\x001\x000\x000\x00_\x006\x004\x00.\x001\x008\x007\x00.\x002\x001\x003\x00.\x001\x009\x004\x00.\x00l\x00n\x00k\x00\x00\x00\x1c\x00'
Item  5
  b'2\x00\x1a\x01\x00\x00\xafR+\xae&\x00desktop.ini\x00H\x00\t\x00\x04\x00\xef\xbe\xaeR\xeb\x01TX.m.\x00\x00\x00\xd9k\x01\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x95\xa35\x00d\x00e\x00s\x00k\x00t\x00o\x00p\x00.\x00i\x00n\x00i\x00\x00\x00\x1a\x00'
Item  6
  b'2\x00\x9c\x04\x00\x00mV\x94\xb0 \x00TOTALC~1.LNK\x00\x00f\x00\t\x00\x04\x00\xef\xbemV\x94\xb0RX\xe1h.\x00\x00\x00\x9bo\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x001\xbf\x01\x01T\x00o\x00t\x00a\x00l\x00 \x00C\x00o\x00m\x00m\x00a\x00n\x00d\x00e\x00r\x00 \x006\x004\x00 \x00b\x00i\x00t\x00.\x00l\x00n\x00k\x00\x00\x00\x1c\x00'
Item  7
  b'2\x00\x8e\x04\x00\x00mV\x94\xb0 \x00TOTALC~2.LNK\x00\x00X\x00\t\x00\x04\x00\xef\xbemV\x94\xb0RX\xe1h.\x00\x00\x00\x9co\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x001\xbf\x01\x01T\x00o\x00t\x00a\x00l\x00 \x00C\x00o\x00m\x00m\x00a\x00n\x00d\x00e\x00r\x00.\x00l\x00n\x00k\x00\x00\x00\x1c\x00'
Spacings: (75, 101), (96, 16)
Item b'\x1fx@\xf0_d\x81P\x1b\x10\x9f\x08\x00\xaa\x00/\x95N' position: (13, 2)
0
16
32
48

Done.

注释

  • 我不知道Win如何将屏幕分成图块,所以我不知道如何使图标在任何迭代中移动(但这超出了问题范围,并且在旧方法中是类似的)。我没有任何特殊原因将 X / Y 坐标增加 16

  • 项目可以通过其数据来指定(在底层 WinAPI 实现中使用)。但由于该数据(上面输出中的乱码字符串)对用户来说毫无意义,因此我添加了使用其索引的功能。如果您想按名称使用它,请检查以下代码(code02.py,来自 [GitHub] 的“窃取”:mhammond/pywin32 - (main) com/win32comext/shell/test/testShellFolder.py):

    #!/usr/bin/env python
    
    import sys
    
    from win32com.shell import shell, shellcon
    
    
    def main(*argv):
        sf = shell.SHGetDesktopFolder()
        print("Shell Folder is", sf, dir(sf))
        for i, e in enumerate(sf):
            print(f"Item: {i}\n  Name: {sf.GetDisplayNameOf(e, shellcon.SHGDN_NORMAL)}\n  Data: {e}")
    
        # And get the enumerator manually
        objs = sf.EnumObjects(0, shellcon.SHCONTF_FOLDERS | shellcon.SHCONTF_NONFOLDERS | shellcon.SHCONTF_INCLUDEHIDDEN)
        print(objs, dir(objs))
    
    
    if __name__ == "__main__":
        print(
            "Python {:s} {:03d}bit on {:s}\n".format(
                " ".join(elem.strip() for elem in sys.version.split("\n")),
                64 if sys.maxsize > 0x100000000 else 32,
                sys.platform,
            )
        )
        rc = main(*sys.argv[1:])
        print("\nDone.\n")
        sys.exit(rc)
    
  • 检查[SO]:如何使用 python 和 win32print 更改打印队列中作业的用户名(@CristiFati 的答案)(最后)以了解如何继续执行上述补丁

  • 没有在新的Win 11版本上尝试它,因为我没有它



原答案

抱歉,我在 [\[MS.Docs\]: LVM\_SETITEMPOSITION message](https://learn.microsoft.com/en-us/windows/win32/controls/lvm) 中误读了 *WORD*(如 *DWORD*) -setitemposition),所以我向左移动了太多。
这是一个工作示例(应该将项目移动到桌面上的主对角线上)。

code00.py

#!/usr/bin/env python

import msvcrt
import sys
import time

import commctrl as cc
import win32gui as wgui


def main(*argv):
    search_criteria = (
        (0, "Progman", None),
        (0, "SHELLDLL_DefView", None),
        (0, "SysListView32", None),
    )
    wnd = 0
    for crit in search_criteria:
        wnd = wgui.FindWindowEx(wnd, *crit)
        if wnd == 0:
            print("Could not find child matching criteria: {:}".format(crit))
            return
    idx = 0
    for i in range(0, 1000, 16):
        lparam = (i << 16) | i
        print("{:d} - 0x{:08X}".format(i, lparam))
        wgui.SendMessage(wnd, cc.LVM_SETITEMPOSITION, idx, lparam)
        time.sleep(0.5)
        if msvcrt.kbhit():
            break


if __name__ == "__main__":
    print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
                                                   64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    rc = main(*sys.argv[1:])
    print("\nDone.")
    sys.exit(rc)
© www.soinside.com 2019 - 2024. All rights reserved.