備忘錄_20160105(定位) 修改 回首頁

程式 2025-04-17 00:48:30 1744822110 100
python 混合 fastapi 與 tkinter 使用

python 混合 fastapi 與 tkinter 使用
這個程式再修整修整,就可以做出 SaveAs 和 Save(不用再詢問) 了

●save.py
# api 
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
import uvicorn
from pydantic import BaseModel # 為了 post

# gui
import tkinter as tk
from tkinter import filedialog

# 協同合作
import threading
import queue
import time
import asyncio
oQueue_to_gui = queue.Queue() 
oQueue_to_api = queue.Queue()
oStopEvent=threading.Event()

class CData(BaseModel):
  strData: str

oMyFastApi = FastAPI()
oMyFastApi.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"]) # 為了 CORS

@oMyFastApi.get("/stop")
def func_stop():
  global oUvicornServer
  oStopEvent.set()
  oUvicornServer.should_exit=True
  return { "訊息": "已送出停止訊息。" }
  
@oMyFastApi.post("/save")
def func_save(oData: CData):
  oQueue_to_gui.put(oData)
  while True:
    time.sleep(0.1)
    if not oQueue_to_api.empty():
      strFilename=oQueue_to_api.get_nowait()
      break
  return { "strFilename": strFilename }

async def run_api():
  oConfig=uvicorn.Config(oMyFastApi, host="0.0.0.0", port=8000)
  global oUvicornServer
  oUvicornServer=uvicorn.Server(oConfig)
  await oUvicornServer.serve()
    
def run_gui():
  while not oStopEvent.is_set():
    time.sleep(0.1)
    if not oQueue_to_gui.empty():
      oData=oQueue_to_gui.get_nowait()
      oRoot=tk.Tk()
      strFilename=filedialog.asksaveasfilename(
        title="儲存檔案",
        defaultextension=".txt",
        filetypes=[("Text files", "*.txt"), ("All files", "*.*")]
      )
      oQueue_to_api.put(strFilename)
      if strFilename!="":
        with open(strFilename, "w", encoding="utf-8", newline='') as oFile:
          oFile.write(oData.strData)
      oRoot.destroy() # 用完關掉 root 視窗



api_thread = threading.Thread(target=lambda: asyncio.run(run_api()), daemon=True)
api_thread.start()

gui_thread = threading.Thread(target=run_gui, daemon=True)
gui_thread.start()

api_thread.join()
gui_thread.join()


●呼叫的 javascript 為
fetch(
  'http://127.0.0.1:8000/save',
  { 
    method: "POST", 
    headers: {"Content-Type": "application/json"}, 
    body: JSON.stringify({ strData: "耶,可以存檔了!\r\n第二行!"})
  }
)
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));