Python 2.7 使用Tkinter(有时)headless或root.after()的替换运行Python

Python 2.7 使用Tkinter(有时)headless或root.after()的替换运行Python,python-2.7,tkinter,headless,Python 2.7,Tkinter,Headless,我有下面的工作代码 我有一套用Python操作的机器。我在Tkinter中有一个gui,但这些机器通常是无头运行的,python代码在启动时自动启动 我非常喜欢使用root.after()启动多个任务并让它们继续运行的设计模式。我的问题是,这来自Tkinter库,当运行headless时,行“root=Tk()”将抛出一个错误 我有两个问题 我可以执行一些技巧让代码忽略没有显示的事实吗 或 是否有与Tkinter“root.after(time_in_ms,function_to_call)”的

我有下面的工作代码

我有一套用Python操作的机器。我在Tkinter中有一个gui,但这些机器通常是无头运行的,python代码在启动时自动启动

我非常喜欢使用root.after()启动多个任务并让它们继续运行的设计模式。我的问题是,这来自Tkinter库,当运行headless时,行“root=Tk()”将抛出一个错误

我有两个问题

  • 我可以执行一些技巧让代码忽略没有显示的事实吗
  • 是否有与Tkinter“root.after(time_in_ms,function_to_call)”的设计模式相匹配的库
  • 我确实试着翻阅Tkinter的底层代码,看看是否有Tkinter包装的另一个库,但我没有能力解码该库中发生的事情

    此代码与连接的显示器一起工作:(它打印hello 11次,然后结束)

    如果在远程计算机的ssh会话中无头运行,则返回此错误消息

    回溯(最后一次调用):文件“tkinter_headless.py”,第行 5,在 root=Tk()文件“/usr/lib/python2.7/lib-Tk/Tkinter.py”,第1813行,在init self.tk=\u tkinter.create(屏幕名、基本名、类名、交互、wantobjects、useTk、同步、使用) _tkinter.TclError:没有显示名称和$display环境变量

    你可以用

    • 穿线
    或者使用自己的
    after()和
    mainloop()创建自己的taks管理器

    简单例子

    import time
    
    class TaskManager():
    
        def __init__(self):
            self.tasks = dict()
            self.index = 0
            self.running = True
    
        def after(self, delay, callback):
            # calcuate time using delay
            current_time = time.time()*1000
            run_time = current_time + delay
    
            # add to tasks
            self.index += 1
            self.tasks[self.index] = (run_time, callback)
    
            # return index
            return self.index
    
        def after_cancel(self, index):
            if index in self.tasks:
                del self.tasks[index]
    
        def mainloop(self):
    
            self.running = True
    
            while self.running:
    
                current_time = time.time()*1000
    
                # check all tasks
                # Python 3 needs `list(self.tasks.keys())` 
                # because `del` changes `self.tasks.keys()`
                for key in self.tasks.keys():
                    if key in self.tasks:
                        run_time, callback = self.tasks[key]
                        if current_time >= run_time:
                            # execute task  
                            callback()
                            # remove from list
                            del self.tasks[key]
    
                # to not use all CPU
                time.sleep(0.1)
    
        def quit(self):
            self.running = False
    
        def destroy(self):
            self.running = False
    
    # --- function ---
    
    def stop_saying_hello():
        global count
        global h
        global c
    
        if count > 10:
            root.after_cancel(h)
            print "counting cancelled"
        else:
            c = root.after(200, stop_saying_hello)
    
    def hello():
        global count
        global h
    
        print "hello", count
        count += 1
    
        h = root.after(1000, hello)
    
    # --- main ---
    
    count = 0
    h = None
    c = None
    
    root = TaskManager()
    
    h = root.after(1000, hello)  # time in ms, function
    c = root.after(200, stop_saying_hello)
    
    d = root.after(12000, root.destroy)
    
    root.mainloop()
    

    什么错误?始终对完整的错误消息提出疑问。请参阅-fake display请参阅
    线程处理
    ,您可以始终在()之后创建自己的
    。它将函数添加到特殊列表中,并且
    mainloop
    一直循环并检查此列表中的元素。在3.4+中,还可以使用asyncio及其等价物执行定时任务。回答非常好。我用xvfb做了一个测试,程序执行起来很好!。我认为定制任务管理器是更好的可维护性解决方案。我可以在代码中使用注释更容易地解释目的。谢谢
    import time
    
    class TaskManager():
    
        def __init__(self):
            self.tasks = dict()
            self.index = 0
            self.running = True
    
        def after(self, delay, callback):
            # calcuate time using delay
            current_time = time.time()*1000
            run_time = current_time + delay
    
            # add to tasks
            self.index += 1
            self.tasks[self.index] = (run_time, callback)
    
            # return index
            return self.index
    
        def after_cancel(self, index):
            if index in self.tasks:
                del self.tasks[index]
    
        def mainloop(self):
    
            self.running = True
    
            while self.running:
    
                current_time = time.time()*1000
    
                # check all tasks
                # Python 3 needs `list(self.tasks.keys())` 
                # because `del` changes `self.tasks.keys()`
                for key in self.tasks.keys():
                    if key in self.tasks:
                        run_time, callback = self.tasks[key]
                        if current_time >= run_time:
                            # execute task  
                            callback()
                            # remove from list
                            del self.tasks[key]
    
                # to not use all CPU
                time.sleep(0.1)
    
        def quit(self):
            self.running = False
    
        def destroy(self):
            self.running = False
    
    # --- function ---
    
    def stop_saying_hello():
        global count
        global h
        global c
    
        if count > 10:
            root.after_cancel(h)
            print "counting cancelled"
        else:
            c = root.after(200, stop_saying_hello)
    
    def hello():
        global count
        global h
    
        print "hello", count
        count += 1
    
        h = root.after(1000, hello)
    
    # --- main ---
    
    count = 0
    h = None
    c = None
    
    root = TaskManager()
    
    h = root.after(1000, hello)  # time in ms, function
    c = root.after(200, stop_saying_hello)
    
    d = root.after(12000, root.destroy)
    
    root.mainloop()