我在一家在本地计算机和服务器上部署系统的公司工作。
给我的任务是创建一个 python 应用程序,它与 plc 通信并使用 Reactjs/Electron.js
显示收集的数据或将数据保存在 MS SQL Server
上。
我的想法是使用 tkinter
创建 gui 并通过创建 <filename>.spec
文件和 pyinstaller
将其转换为应用程序,看起来像 XAMPP
,我可以在其中重新启动和启动api。
如果我使用 tkinter
我应该从哪里开始?当 gui 打开时,我设法启动了后端,但我不知道停止或重新启动后端。我对 threads
也没有太多想法,但我认为它会帮助我创造我想要的东西。
我也在寻找是否可以使用 XAMPP
作为主机来运行 api 但没有运气。
如果你们有更好的方法在没有 cmd 的情况下在本地主机上运行 api 真的会有所帮助
答案 0 :(得分:0)
好的,所以这花了一段时间,但我想出了如何不使用 subprocess
(主要是因为还有另一个关于不使用 python
的问题,所以唯一的方法是将烧瓶应用程序转换为 { {1}} 然后使用 .exe
但我发现如何只使用 python 来做到这一点),主要问题(简单的修复,但在使用 subprocess
时也必须解决)是烧瓶重新启动服务器启动另一个进程,因此您必须在 subprocess.Popen
方法中使用 use_reloader=False
。评论中的解释:
app.py
.run()
run.py
# import what's necessary
from flask import Flask, render_template_string, url_for
from flask import request
app = Flask(__name__)
# sample route
@app.route('/')
def home():
return render_template_string('<a href="{{ url_for("about") }}">To About Page</a>'
'<h1>Home Page</h1>')
# sample route
@app.route('/about')
def about():
return render_template_string('<a href="{{ url_for("home") }}">To Home Page</a>'
'<h1>About Page</h1>')
# important route that will do the stopping part since that was a requirement in the question
# link to this in the answer at the bottom
@app.route('/kill_server', methods=['GET'])
def kill_server():
func = request.environ.get('werkzeug.server.shutdown')
if func is None:
raise RuntimeError('Not running with the Werkzeug Server. Could not shut down server.')
func()
return 'Server shutting down...'
# to prevent this from running when importing
if __name__ == '__main__':
app.run(debug=True)
来源:
唯一的问题是在控制台中显示启动消息,有一种方法可以通过将 # import all that is necessary
from tkinter import Tk, Text, Button, Frame
from for_so_dir.app import app as server
from threading import Thread
from queue import Queue, Empty
import requests
import logging.handlers
# simple dictionary to avoid using `global`, just a preference of mine
info = {'server_is_running': False}
# the function that starts server (multiprocessing is not possible with flask as far as I know)
# basically checks if the server is not running already and if it is not then starts a thread
# with the server (which is the same as `app` in the app.py) and sets that server is running
def start_server():
if info['server_is_running']:
return
Thread(target=server.run, kwargs={'debug': True, 'use_reloader': False}, daemon=True).start()
info['server_is_running'] = True
# function from stopping server, again in the answer at the bottom, but basically
# this sends a request to the server and that request executes a function
# that stops the server
def stop_server():
if not info['server_is_running']:
return
requests.get('http://127.0.0.1:5000/kill_server')
# function for showing the logs in the Text widget, it simply tries to get data from
# the queue (if there is nothing it simply loops again) and then inserts that data into
# the text widget
def update_text_log():
try:
data = queue.get(block=False)
except Empty:
pass
else:
log.config(state='normal')
log.insert('end', data.msg + '\n')
log.config(state='disabled')
finally:
root.after(100, update_text_log)
# this `if statement` is not that necessary in the current code but it might as well
# stay here
if __name__ == '__main__':
# initialise the Queue
queue = Queue()
# now the main part, to get the info from flask you need to use `logging`
# since that is what it uses for all the messages, and use the `QueueHandler`
# to put the messages in the queue and then update them using the above
# function
logging.basicConfig(handlers=(logging.handlers.QueueHandler(queue), ))
# simple `tkinter` stuff
root = Tk()
# this part can be removed or made toggleable but it allows to easier see how
# this works in action
root.attributes('-topmost', True)
log = Text(root, state='disabled')
log.pack(expand=True, fill='both')
update_text_log()
button_frame = Frame(root)
button_frame.pack(fill='x')
Button(button_frame, text='Start Server', command=start_server).pack(expand=True, fill='x', side='left')
Button(button_frame, text='Stop Server', command=stop_server).pack(expand=True, fill='x', side='right')
root.mainloop()
然后 import os
添加到 os.environ['WERKZEUG_RUN_MAIN'] = 'true'
文件来删除它,但有一个小问题然后使用按钮停止服务器将执行以下操作:app.py
(至少在 Windows 上)因此您必须找到一种方法来解决此问题,因为我还不能这样做