我想要一个实现HTTP API(例如使用Flask)的Python程序,在该程序上它可以接收消息以在屏幕上显示各种窗口(例如使用tkinter)。
构造这样一个程序的好方法是什么?我相信我将需要两个单独的线程:一个用于绘制tkinter窗口,另一个用于侦听HTTP请求。
例如,我想发送http请求到/ show_window,然后显示一个窗口并保持在屏幕上,直到将请求发送到/ hide_window,然后关闭该窗口。
我可以通过tkinter绘制窗口。但是,如果我把它放在Flask路由中,则当然会卡在window.mainloop()上。
import tkinter as tk
from flask import Flask
app = Flask(__name__)
@app.route("/show")
def show():
root = tk.Tk()
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
root.attributes('-alpha', 0.0) #For icon
root.iconify()
window = tk.Toplevel(root)
window.geometry("%sx%s" % (screen_width, screen_height))
window.configure(background='black', cursor='none')
window.overrideredirect(1)
window.attributes('-topmost', 1)
close = tk.Button(window, text = "Close Window", command = lambda: root.destroy())
close.pack(fill = tk.BOTH, expand = 0)
window.mainloop() # app is stuck here until gui window is closed
return "show!"
@app.route("/hide")
def hide():
### Code to destroy or hide the Window here.
return "hide"
我想我需要两个线程:一个运行Flask的线程+一个启动窗口的线程,然后flask线程需要将消息发送到窗口线程以显示,隐藏,创建,销毁窗口,等等 但是我不确定如何做到这一点。
请注意,绝对不需要使用Flask或tkinter。对于API的简单Web框架和创建GUI窗口的简单方法来说,这只是工具。
答案 0 :(得分:1)
您确实需要单独的线程。
这是对我有用的方法。它涉及到在单独的线程中启动Flask应用程序,然后使用诸如threading.Event
之类的东西与前台GUI线程进行通信,或者使用threading.Lock
之类的东西来控制对共享数据结构的访问。
在线程中启动Flask应用很简单,看起来像
import threading
import time
from yourapp import app
def webserver(shared_state):
app.config['SHARED'] = shared_state
# It isn't safe to use the reloader in a thread
app.run(host='127.0.0.1', debug=True, use_reloader=False)
def main():
shared_state = SharedState()
ui_thread = threading.Thread(target=webserver, args=(shared_state,))
ui_thread.start()
while shared_state.running():
time.sleep(0.1)
if shared_state.button_clicked():
# do your Tk popup here
ui_thread.join()
if __name__ == '__main__':
main()
(这是“自旋锁定”方法。请登录threading.Event
以使用其他方法。)
有趣的是共享状态对象,它使用线程锁序列化对共享数据的访问(在此示例中为点击计数器)
class SharedState:
def __init__(self):
self._lock = threading.Lock()
self._running = True
self._click_count = 0
def record_click(self):
# this gets called from the Flask thread to record a click
with self._lock:
self._click_count += 1
def clicked(self):
# this gets called from the GUI thread to 'get' a click
with self._lock:
if self._click_count > 0:
self._click_count -= 1
return True
return False
def stop(self):
# called from either side to stop running
with self._lock:
self._running = False
烧瓶侧面(在yourapp.py
中)的作用类似
app = Flask(__name__)
@app.route('/')
def home():
if request.method == 'POST':
app.config['SHARED'].record_click()
return render_response('index.html')
从Flask端停止应用程序要比仅在共享控件上调用.stop()
棘手。请参见here,以获取执行此操作的代码。