Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/353.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/19.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代码在与PyWin32混合时会崩溃?_Python_Crash_Tkinter_Clipboard_Pywin32 - Fatal编程技术网

Python 为什么这个有效的Tkinter代码在与PyWin32混合时会崩溃?

Python 为什么这个有效的Tkinter代码在与PyWin32混合时会崩溃?,python,crash,tkinter,clipboard,pywin32,Python,Crash,Tkinter,Clipboard,Pywin32,所以我在tkinter做了一个非常小的程序供个人使用,我遇到了一堵非常奇怪的墙。我把tkinter和pywin32绑定混合在一起,因为我真的很讨厌pywin32的语法和命名约定,而且感觉tkinter可以用更少的代码完成更多的工作。奇怪的是在pywin32剪贴板监视和我的程序在tkinter中对它的反应之间的转换过程中发生的 我的窗口及其所有控件都在tkinter中处理。当剪贴板更改时,pywin32绑定正在执行剪贴板监视和剪贴板访问。从我收集的有关剪贴板监视pywin32片段的工作方式的信息来

所以我在tkinter做了一个非常小的程序供个人使用,我遇到了一堵非常奇怪的墙。我把tkinter和pywin32绑定混合在一起,因为我真的很讨厌pywin32的语法和命名约定,而且感觉tkinter可以用更少的代码完成更多的工作。奇怪的是在pywin32剪贴板监视和我的程序在tkinter中对它的反应之间的转换过程中发生的

我的窗口及其所有控件都在tkinter中处理。当剪贴板更改时,pywin32绑定正在执行剪贴板监视和剪贴板访问。从我收集的有关剪贴板监视pywin32片段的工作方式的信息来看,只要为pywin32提供窗口的hwnd值,您就可以使它与任何您想要的东西一起工作。我正在做那部分,当程序第一次启动时它就开始工作了。当剪贴板更改时,它似乎不起作用

当程序启动时,它抓取剪贴板并将其放入搜索框和编辑框中。当剪贴板被修改时,我想触发的事件正在触发…除了在程序启动之前完全有效的事件现在导致了奇怪的挂起,而不是它应该做的事情。如果剪贴板发生更改,我可以将剪贴板内容打印到标准,但不能将相同的数据放入tkinter小部件中。只有当它在被剪贴板更改通知触发后开始与我的tkinter小部件交互时,它才会像这样挂起

在将我正在使用的示例代码调整到tkinter使用程序中时,我感觉有一些pywin32礼仪我错过了。Tkinter显然不喜欢生成堆栈跟踪或错误消息,而且我甚至都不知道如何使用pdb调试它

代码如下:

#coding: utf-8
#Clipboard watching cribbed from ## {{{ http://code.activestate.com/recipes/355593/ (r1)

import pdb
from Tkinter import *
import win32clipboard
import win32api
import win32gui
import win32con
import win32clipboard


def force_unicode(object, encoding="utf-8"):
    if isinstance(object, basestring) and not isinstance(object, unicode):
        object = unicode(object, encoding)
    return object

class Application(Frame):
    def __init__(self, master=None):
        self.master = master
        Frame.__init__(self, master)
        self.pack()
        self.createWidgets()

        self.hwnd = self.winfo_id()
        self.nextWnd = None
        self.first = True
        self.oldWndProc = win32gui.SetWindowLong(self.hwnd, win32con.GWL_WNDPROC, self.MyWndProc)
        try:
            self.nextWnd = win32clipboard.SetClipboardViewer(self.hwnd)
        except win32api.error:
            if win32api.GetLastError () == 0:
                # information that there is no other window in chain
                pass
            else:
                raise

        self.update_search_box()
        self.word_search()

    def word_search(self):
        #pdb.set_trace()
        term = self.searchbox.get()
        self.resultsbox.insert(END, term)

    def update_search_box(self):
        clipboardtext = ""
        if win32clipboard.IsClipboardFormatAvailable(win32clipboard.CF_TEXT):
            win32clipboard.OpenClipboard()
            clipboardtext = win32clipboard.GetClipboardData()
            win32clipboard.CloseClipboard()

        if clipboardtext != "":
            self.searchbox.delete(0,END)
            clipboardtext = force_unicode(clipboardtext)
            self.searchbox.insert(0, clipboardtext)

    def createWidgets(self):
        self.button = Button(self)
        self.button["text"] = "Search"
        self.button["command"] = self.word_search

        self.searchbox = Entry(self)
        self.resultsbox = Text(self)

        #Pack everything down here for "easy" layout changes later
        self.searchbox.pack()
        self.button.pack()
        self.resultsbox.pack()

    def MyWndProc (self, hWnd, msg, wParam, lParam):
        if msg == win32con.WM_CHANGECBCHAIN:
            self.OnChangeCBChain(msg, wParam, lParam)
        elif msg == win32con.WM_DRAWCLIPBOARD:
            self.OnDrawClipboard(msg, wParam, lParam)

        # Restore the old WndProc. Notice the use of win32api
        # instead of win32gui here. This is to avoid an error due to
        # not passing a callable object.
        if msg == win32con.WM_DESTROY:
            if self.nextWnd:
               win32clipboard.ChangeClipboardChain (self.hwnd, self.nextWnd)
            else:
               win32clipboard.ChangeClipboardChain (self.hwnd, 0)

            win32api.SetWindowLong(self.hwnd, win32con.GWL_WNDPROC, self.oldWndProc)

        # Pass all messages (in this case, yours may be different) on
        # to the original WndProc
        return win32gui.CallWindowProc(self.oldWndProc, hWnd, msg, wParam, lParam)

    def OnChangeCBChain (self, msg, wParam, lParam):
        if self.nextWnd == wParam:
           # repair the chain
           self.nextWnd = lParam
        if self.nextWnd:
           # pass the message to the next window in chain
           win32api.SendMessage (self.nextWnd, msg, wParam, lParam)

    def OnDrawClipboard (self, msg, wParam, lParam):
        if self.first:
           self.first = False
        else:
            #print "changed"
            self.word_search()
            #self.word_search()

        if self.nextWnd:
           # pass the message to the next window in chain
           win32api.SendMessage(self.nextWnd, msg, wParam, lParam)


if __name__ == "__main__":
    root = Tk()
    app = Application(master=root)
    app.mainloop()
    root.destroy()

不确定它是否有帮助,但我假设它在您从win32事件处理程序中调用更新时发生故障,tkinter可能不喜欢这样

通常的解决方法是通过after_idle()回调延迟更新

因此,尝试替换:

   def OnDrawClipboard (self, msg, wParam, lParam):
    if self.first:
       self.first = False
    else:
        #print "changed"
        self.word_search()
        #self.word_search()

    if self.nextWnd:
       # pass the message to the next window in chain
       win32api.SendMessage(self.nextWnd, msg, wParam, lParam)
为此:

   def OnDrawClipboard (self, msg, wParam, lParam):
    if self.first:
       self.first = False
    else:
        #print "changed"
        self.after_idle(self.word_search)
        #self.word_search()

    if self.nextWnd:
       # pass the message to the next window in chain
       win32api.SendMessage(self.nextWnd, msg, wParam, lParam)

我认为这可能会起作用,但我必须在某种主循环中进行轮询,以使用放置在别处的布尔变量触发更新。我感谢你试图回答这个问题。在这么长时间没有回应后,我只是将整个项目转换为wxPython。我真的不太喜欢wxPython,但是对于这个小项目来说,完全采用它就不那么令人头痛了。