使用tkinter来查看剪贴板,我的代码出了什么问题?

时间:2013-03-23 17:59:01

标签: python multithreading python-3.x tkinter clipboard

关于代码的一些描述:

  1. 这是我的计划的一部分,我只把相关的行放在这里
  2. 我希望这些代码可以做的是查看我的剪贴板。如果我将“ http:xxx ”复制到我的剪贴板,它会显示一个弹出窗口。如果内容为剪贴板不会改变,窗口不会再显示
  3. 运行时,它可以正常弹出窗口一次,但是当我将另一个字符串复制到剪贴板时,不会再次执行此操作'http:'
  4. 我在after方法中尝试了一些不同的区间值,结果相同。
  5. 代码:

    from tkinter import *
    import os
    import tkinter.messagebox as messagebox
    import threading
    import re
    
    def watch_clipboard(tk,pipeout):  
        content = '' 
        last_content = ''
        while True:
            try:
                content = tk.clipboard_get()
            except TclError:
                pass
            result = re.match('http:',content)
            if content != last_content:
                if result:
                    last_content = content
                    message = 'show'.encode()    
                    os.write(pipeout,message)
    
    
    class GUI:
        def __init__(self):
            self.tk = Tk()
            self.tk.resizable(0, 0)
            self.tk.title('watch clipboard')
            pipein,pipeout = os.pipe()
            threading.Thread(target=watch_clipboard,daemon=True,args=(self.tk,pipeout)).start()
            self.tk.after(5000,lambda:self.clipboard_confirm(pipein))
            self.tk.mainloop()
    
        def clipboard_confirm(self,pipein):
            message = os.read(pipein,16)
            if message == b'show':
                self.tk.clipboard_clear()
                messagebox.askokcancel('', 'add this in?', default='ok')
                self.tk.after(5000,clipboard_confirm(pipein))   #add this
    
    
    if __name__ == '__main__':
        gui = GUI()
    

    编辑:甲。罗达斯的代码有效。似乎多线程导致问题。深层原因仍然未知。

3 个答案:

答案 0 :(得分:1)

我认为多线程不适合您的情况,而after可能就足够了。您可以使用较低的超时时间调用tk.after,而不是繁忙的等待循环。然后你只需要将watch_clipboard的逻辑移到你的班级,这样你就不用担心线程之间的通信了。

class GUI:
    def __init__(self):
        self.tk = Tk()
        self.tk.resizable(0, 0)
        self.tk.title('watch clipboard')
        self.last_content = ''
        self.tk.after(100, self.watch_clipboard)
        self.tk.mainloop()
    def watch_clipboard(self):
        try:
            content = self.tk.clipboard_get()
            if content != self.last_content and content.startswith('http:'):
                self.last_content = content
                self.tk.clipboard_clear()
                messagebox.askokcancel('', 'add this in?', default='ok')
        except TclError:
            pass
        self.tk.after(100, self.watch_clipboard)

答案 1 :(得分:1)

@ laike9m
您的代码错误是使用了os.pipe。
Os.read()是一个阻塞函数,一旦运行clipboard_confirm,它将接收os.read()阻塞。导致UI卡住。
此错误与after和多线程无关。

答案 2 :(得分:0)

问题很可能与使用线程有关 - 从主线程以外的任何地方调用Tkinter函数都可能导致问题。

你是否有理由使用线程而不是利用内置的无限循环(事件循环)?我建议每隔一秒钟使用after来检查键盘。