运行 Python 使用 Tkinter(有时)无头或替换 root.after()
Run Python with Tkinter (sometimes) headless OR replacement for root.after()
我有下面的工作代码。
我有一套用Python操作的机器。我在 Tkinter 中有一个 gui,但这些机器经常 运行 无头, python 代码在启动时自动启动。
我非常喜欢使用 root.after() 启动多个任务并让它们继续运行的设计模式。我的问题是,这来自 Tkinter 库,当 运行ning headless 行 "root=Tk()" 将抛出错误。
我有两个问题
- 我可以执行一些技巧让代码忽略没有显示的事实吗?
或
- 是否有符合 Tkinter 设计模式的库 "root.after(time_in_ms,function_to_call)"。
我确实尝试查看 Tkinter 的底层代码,看看是否有另一个库被 Tkinter 包装,但我没有解码该库中发生的事情的技能。
此代码适用于已连接的显示器:(打印 hello 11 次然后结束)
from Tkinter import *
# def __init__(self, screenName=None, baseName=None, className='Tk', useTk=1, sync=0, use=None):
root = Tk() # error is thrown here if starting this command in headless hardware setup
h = None
count = 0
c = None
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 h
global count
print "hello " + str(count)
count += 1
h = root.after(1000, hello)
h = root.after(1000, hello) # time in ms, function
c = root.after(200, stop_saying_hello)
root.mainloop()
如果这是 运行 headless - 在来自远程计算机的 ssh 会话中,则会返回此错误消息
Traceback (most recent call last): File "tkinter_headless.py", line
5, in
root = Tk() File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 1813, in init
self.tk = _tkinter.create(screenName, baseName, className, interactive, wantobjects, useTk, sync, use)
_tkinter.TclError: no display name and no $DISPLAY environment variable
您可以使用
threading
和 threating.timer()
- shed
- APSheduler
或使用自己的 after()
和 mainloop()
创建自己的任务管理器
简单示例
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()
我有下面的工作代码。
我有一套用Python操作的机器。我在 Tkinter 中有一个 gui,但这些机器经常 运行 无头, python 代码在启动时自动启动。
我非常喜欢使用 root.after() 启动多个任务并让它们继续运行的设计模式。我的问题是,这来自 Tkinter 库,当 运行ning headless 行 "root=Tk()" 将抛出错误。
我有两个问题
- 我可以执行一些技巧让代码忽略没有显示的事实吗?
或
- 是否有符合 Tkinter 设计模式的库 "root.after(time_in_ms,function_to_call)"。
我确实尝试查看 Tkinter 的底层代码,看看是否有另一个库被 Tkinter 包装,但我没有解码该库中发生的事情的技能。
此代码适用于已连接的显示器:(打印 hello 11 次然后结束)
from Tkinter import *
# def __init__(self, screenName=None, baseName=None, className='Tk', useTk=1, sync=0, use=None):
root = Tk() # error is thrown here if starting this command in headless hardware setup
h = None
count = 0
c = None
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 h
global count
print "hello " + str(count)
count += 1
h = root.after(1000, hello)
h = root.after(1000, hello) # time in ms, function
c = root.after(200, stop_saying_hello)
root.mainloop()
如果这是 运行 headless - 在来自远程计算机的 ssh 会话中,则会返回此错误消息
Traceback (most recent call last): File "tkinter_headless.py", line 5, in root = Tk() File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 1813, in init self.tk = _tkinter.create(screenName, baseName, className, interactive, wantobjects, useTk, sync, use) _tkinter.TclError: no display name and no $DISPLAY environment variable
您可以使用
threading
和 threating.timer()- shed
- APSheduler
或使用自己的 after()
和 mainloop()
简单示例
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()