一、准备工作
使用图形开发界面库(如Tkinter、PyQt)制作一个GUI文件,然后还是使用flask制作后端,使用request发送同步申请,使用pymysql来连接数据库,重点依然是数据库的连接以及同步申请的方法。
安装好以下Python库
# flask文件中
from flask import Flask, request, jsonify, send_from_directory
import pymysql
from flask_cors import CORS
import os
import subprocess
# GUI文件中
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
import json
import requests
二、开始
2.1 GUI文件的编写
我简单的写了两个功能,一个是添加数据,一个是查询数据,使用request库发送同步申请(由于是简单的,因此没有使用异步申请请求,如果想要发送异步请求的话,使用asyncio和aiohttp库),接收从后端返回的数据,由于不是web端,因此代码和处理方式也不同,个人认为这个比web要难。
class MyApp(tk.Tk):
def __init__(self):
super().__init__()
# 初始化界面
self.title('数据添加和查询示例')
self.geometry('400x300')
# 布局
self.create_layout()
def create_layout(self):
# 添加数据部分
self.name_label_add = ttk.Label(self, text='姓名:')
self.name_input_add = ttk.Entry(self)
self.add_button = ttk.Button(self, text='添加数据', command=self.add_data)
self.name_label_add.pack()
self.name_input_add.pack()
self.add_button.pack()
# 查询数据部分
self.query_button = ttk.Button(self, text='查询数据', command=self.query_data)
self.result_label = ttk.Label(self, text='查询结果:')
self.result_browser = tk.Text(self, height=10, width=45,font=('SimSun', 12))
self.query_button.pack()
self.result_label.pack()
self.result_browser.pack()
def add_data(self):
name = self.name_input_add.get()
if name:
success = self.send_request('/api/add_data', {'name': name}, 'Data added successfully')
if success:
messagebox.showinfo('Success', 'Data added successfully')
self.name_input_add.delete(0, 'end') # 清空输入框
else:
messagebox.showwarning('Error', 'Name is required')
def query_data(self):
success, data = self.send_request('/api/query_data', None, 'Data queried successfully')
if success:
messagebox.showinfo('Success', 'Data queried successfully')
# 解析 JSON 字符串为 Python 对象
parsed_data = json.loads(data)
# 提取每个字典中的 'name' 值
names = [entry['name'] for entry in parsed_data['data']]
self.result_browser.delete('1.0', 'end') # 清空文本框
# 插入处理后的数据到 Text 组件
for name in names:
self.result_browser.insert('1.0', f"'name': '{name}'\n")
def send_request(self, endpoint, data, success_message):
url = 'http://localhost:5000' + endpoint
headers = {'Content-Type': 'application/json'}
try:
response = requests.post(url, data=json.dumps(data), headers=headers) if data else requests.get(url)
response.raise_for_status()
data = response.text
# Debugging: Print request details
print(f"Sending {'POST' if data else 'GET'} request to: {url}")
return True, data
except requests.exceptions.RequestException as e:
self.show_message(f'Error: {str(e)}')
return False, None
def show_message(self, message):
self.result_browser.delete('1.0', 'end') # 清空文本框
self.result_browser.insert('1.0', message)
print(message)
messagebox.showerror('Error', message) # 你可以选择弹出错误对话框
if __name__ == '__main__':
app = MyApp()
app.mainloop()
里面的知识点比较碎,在此我不再过多赘述。
2.2 flask文件的编写
这次的flask文件与上次的文件略微有些不同,大的地方相同,但是有一些细微的差别。
2.2.1 跨域问题
如果请求你的程序的源和你的程序不在同一个域,就会触发跨域问题,防止其他人获得你的敏感数据。
CORS(app, resources={r"/api/*": {"origins": "*"}})
上述代码就是解决跨域问题的配置,这个配置的含义是允许所有以/api/开头的路径的资源被任何域的请求访问,也可以根据你的要求自行更改。
2.2.2 图标问题
你可以给你的GUI界面设置图标,具体效果看后面结果展示,让你的GUI界面更生动。
# 处理 /favicon.ico 路径的请求
@app.route('/favicon.ico')
def favicon():
return send_from_directory(os.path.join(app.root_path, 'static'),
'favicon.ico', mimetype='image/vnd.microsoft.icon')
需要注意的是,可以使用其他类型的图片(例如:png、jepg等),但是需要进行相应的修改(URL、文件名、MIME类型等等)。
2.2.3 其他问题
使用try except来捕捉异常,使用输出语句来对申请是否到达以及是否成功与数据库交换数据等来进行判断。
app = Flask(__name__)
CORS(app, resources={r"/api/*": {"origins": "*"}})
# MySQL连接配置
db_config = {
'host': 'localhost',
'user': 'root',
'password': '123456',
'database': 'mine',
'cursorclass': pymysql.cursors.DictCursor
}
def get_connection():
return pymysql.connect(**db_config)
# 处理 /favicon.ico 路径的请求
@app.route('/favicon.ico')
def favicon():
return send_from_directory(os.path.join(app.root_path, 'static'),
'favicon.ico', mimetype='image/vnd.microsoft.icon')
@app.route('/api/add_data', methods=['POST'])
def add_data():
try:
data = request.json
# debugging
print(f"Received POST request at /api/add_data with data: {data}")
name = data.get('name')
if name:
# 插入数据到数据库
with get_connection() as connection:
with connection.cursor() as cursor:
cursor.execute('INSERT INTO users(name) VALUES (%s)', (name,))
connection.commit()
return jsonify({'success': True, 'message': 'Data added successfully'})
else:
return jsonify({'success': False, 'message': 'Name is required'})
except Exception as e:
# debugging
print(f"Error processing /api/add_data request: {e}")
return jsonify({'success': False, 'message': str(e)})
@app.route('/api/query_data', methods=['GET'])
def query_data():
try:
# debugging
print("Received GET request at /api/query_data")
# 查询所有数据
with get_connection() as connection:
with connection.cursor() as cursor:
cursor.execute('SELECT * FROM users ORDER BY id DESC')
data = cursor.fetchall()
return jsonify({'success': True, 'data': data})
except Exception as e:
# debugging
print(f"Error processing /api/query_data request: {e}")
return jsonify({'success': False, 'message': str(e)})
if __name__ == '__main__':
# 启动 Gunicorn 服务器
command = [
"waitress-serve",
"--listen=127.0.0.1:5000", # 设置绑定的地址和端口
"flasks:app" # 指定要运行的应用
]
subprocess.run(command)
需要注意的是,我使用的是 Gunicorn服务器,因为之前在调试的时候出现过问题,之后修改了问题后也没有改回去,你使用app.run()也是可以的,不过最好加上debug=True哦。
2.2.4 结果展示
需要注意的是,启动文件的时候应该先启动flask文件,因为flask文件需要监听端口号,来监听是否有申请传来以及处理HTTP请求。
这里还有一个问题就是,如果你的代码没有什么问题,但是还是发生错误,也许是防火墙的问题(这个我就不再细说了,我也不太懂),还有可能就是网络配置的问题。
# 使用ping命令测试网络连接
ping <目标IP地址或域名>
# 使用traceroute命令检查到目标的网络路径
traceroute <目标IP地址或域名>
# 检查服务器连接测试
Test-NetConnection -ComputerName <ip地址> -Port <端口号>
# 确保DNS设置正确
nslookup <域名>
或
dig <域名>
这些都是一些简单的检查网络配置的命令,如果都检查了还没有解决问题就有可能是其他问题了。
下面就是真正的结果展示。
两个功能都是可以正常使用的,但是需要注意你的数据库有相应的表并且SQL语句没有错误。
三、结语
结果看似很简单的一个GUI界面,但是背后做了非常多的工作,所以这份学习和工作是很苦很累的,不过既然选择了它,那就要义无反顾的坚持走下去,加油ヾ(◍°∇°◍)ノ゙