Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/356.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python tkinter watch剪贴板GetMessage无返回值_Python_Winapi_Tkinter_Clipboard - Fatal编程技术网

Python tkinter watch剪贴板GetMessage无返回值

Python tkinter watch剪贴板GetMessage无返回值,python,winapi,tkinter,clipboard,Python,Winapi,Tkinter,Clipboard,我想监视win10的剪贴板应用程序。 比如:当我们从notepad.exe复制文本00-22-33-11-22 Mac地址时,tk的窗口会获取文本并将Mac地址转换为机器名 但是tkinter没有剪贴板事件。 所以我调用win32api 我搜索pywin32文档,找到了Win32 Clipboard.SetClipboardViewer 但是创建剪贴板查看器窗口非常复杂 我搜索MSDN,发现建议使用AddClipboardFormatListener。此方法比设置ClipboardViewer更

我想监视win10的剪贴板应用程序。 比如:当我们从notepad.exe复制文本00-22-33-11-22 Mac地址时,tk的窗口会获取文本并将Mac地址转换为机器名

但是tkinter没有剪贴板事件。 所以我调用win32api 我搜索pywin32文档,找到了Win32 Clipboard.SetClipboardViewer 但是创建剪贴板查看器窗口非常复杂 我搜索MSDN,发现建议使用AddClipboardFormatListener。此方法比设置ClipboardViewer更简单。 我使用了它,但GetMessage总是被阻止

import tkinter as tk
import time
import threading as thrd
import win32gui
import win32clipboard
import win32api
import win32con
import ctypes
from ctypes.wintypes import MSG
from ctypes import byref


def selfevent(root):
    print("thrd start")
    hwnd = int(root.frame(), 16)
    done = ctypes.windll.user32.AddClipboardFormatListener(hwnd)
    print("done=", done)
    if done:
        wmsg = None
        print("begin GetMessage")
        wmsg = win32gui.GetMessage(None, 0, 0)
        # wmsg = MSG()
        # ctypes.windll.user32.GetMessageA(byref(wmsg), 0, 0, 0)
        print("GetMessage", wmsg.message(), win32api.GetLastError())
        if wmsg:
            print("msg=", wmsg)
            print(ctypes.windll.user32.RemoveClipboardFormatListener(hwnd))


if __name__ == "__main__":
    root = tk.Tk()
    root.title("tktest")
    root.geometry("600x400")
    # root.bind("<<foo>>", vectrl)
    print("begin")
    txt = tk.Entry(root)
    txt.pack()
    bt2 = tk.Button(root, text="GetClipboardSequenceNumber", command=lambda: print("sn=", win32clipboard.GetClipboardSequenceNumber()))
    bt2.pack()
    t = thrd.Thread(target=selfevent, args=(root,))
    t.setDaemon(True)
    t.start()
    root.mainloop()
我复制任何东西,GetMessage总是被阻止,不返回。 AddClipboardFormatListener已成功。 GetMessagehwnd或无,0,0 结果是一样的。

我研究过GetMessage,在主线程中,使用AddClipboardFormatListener注册,使用GetMessage是正常的,但在新线程中,GetMessage始终没有返回值。 我回顾了许多论坛帖子,基本上提到了tk的多线程存在问题。 @我读到斯托夫提到了这篇文章。我认为事后不是一个好主意。 之后会消耗主线程性能并影响UI显示。 在vb.net中使用事件在页面上进行通信。因此,我搜索了tk文档并找到了event_generate。 测试发现,事件_generate似乎不受多线程的影响。 通过论坛帖子,我完成了event_generate的一些缺陷,并给出了我的解决方案

我的代码演示了监视剪贴板和启动多线程任务,按钮遍历路径目录中的所有文件,查找文件总数,UI显示不受任务阻塞的影响

将tkinter作为tk导入 将tkinter.ttk导入为ttk 导入Win32剪贴板 将线程作为thrd导入 导入时间 导入操作系统 从队列导入队列 def watchCliptop: lastid=None printStartWatch 尽管如此: 时间0.01 nowid=win32clipboard.GetClipboardSequenceNumber printnowid,lastid 如果不是lastid或lastid!=诺维德: lastid=nowid top.event_generate,when=tail def workButtontop、路径、出队: allcount=0 printStartSearch 对于os.walkpath中的根目录、目录和文件: allcount+=lenfile 顶部。请清除 top.clipboard\u appendallcount outQueue.put\u nowaitallcount top.event_generate,data={result:allcount},when=tail top.event_generate,data=fresult={allcount},when=tail def bind_event_datawidget,sequence,func,add=None: def_替换*参数: def evt: 返回带有_dict的非最简单对象__ 尝试: evt.data=evalargs[0] 除例外情况外: evt.data=args[0] evt.widget=widget 返回evt, funcid=widget.\u registerfunc,\u substitute,needcleanup=1 cmd='{0}如果{[{1}%d]==break}}break\n'。如果add else,则格式化'+',funcid widget.tk.调用'bind',widget.\u w,sequence,cmd 如果uuuu name uuuuu==\uuuuuuuu main\uuuuuuuu: top=tk.tk top.titletktest 顶面几何300x200 rsltQueue=队列 顶端绑定,向量 打印开始 lbl=tk.Labeltop,text=clipboard,width=30,height=3 lbl.pack lblrslt=tk.Labeltop,text=SearchResult,width=40,height=3 lblrslt.pack prb=ttk.Progressbartop,长度=100,模式=不确定 prb.pack txt=tk.Entrytop,宽度=20 txt.pack prb.startinterval=10 t=thrd.Threadtarget=watchClip,args=top,daemon=True t、 开始 def搜索路径: t=thrd.Threadtarget=workButton,args=top,c:,rsltQueue,daemon=True t、 开始 bt2=tk.buttonop,text=SearchPath,command=SearchPath bt2.pack clipText= def dealcue事件: 全局clipText 尝试: clipText=top.clipboard\u get 除了tk.TclError: 通过 lbl[text]=clipText def dealSFevent: lblrslt[text]=fallFileCount={rsltQueue.get} lblrslt[text]=事件.数据[结果] lblrslt[text]=事件数据 顶,顶,顶,顶 顶,顶,顶 绑定\u事件\u数据顶端,dealSF 主循环 Python 3.7.2,操作系统win10 1151,测试通过。连续点击按钮,打开12个工作线程,未发现问题,UI线程流畅 如果代码有意外错误,请检查python安装目录中的tk*.dll。 有信息表明tk86t.dll支持多线程,但不支持tk86.dll。 感谢@FabienAndre、@BryanOakley、@stovfl和所有参与讨论的人。你给了我解决这个问题的灵感。
如果您觉得此解决方案有一些缺陷,请告诉我。

我们可以看看为什么它不能“获取消息”吗?如果我们不知道实际的错误,那么我们就无法真正帮助您调试。对GetMessage的调用会被阻塞,因为线程没有接收任何排队的消息。这种行为是意料之中的。我可能会创建一个线程,创建一个只显示消息的窗口,并侦听更新消息
在该线程中执行的消息循环中。良好的Win32编程基础至关重要。我认为当我复制文本时,win系统应该将消息WM_CLIPBOARDUPDATE发送到根窗口。我想通过GetMessage获取消息。但是,GetMessage在任何情况下都不会收到任何消息。如何修改代码以获取消息?@DavidHeffernan您能给我一个简单的示例代码,用pywin32创建一个不可见窗口并获取“WM_CLIPBOARDUPDATE”消息吗?不,我不能。我相信,如果您做一些研究,您可以找到Python代码来完成所有不同的部分。
begin
thrd start
done= 1
begin GetMessage