关于Python实现画图功能并且实现通信,就是客户端给服务端发送函数方程然后服务端就可以画出图形,然后也可以反过来发送

这串代码比较长,但是出问题的只是其中的一段,也就是open_Windows3这个函数

import tkinter as tk
import sqlite3
import os
import socket
import threading
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import time
#last_a = ''
#send_flag = False
#fig = None
#client_socket = None
class App:
    def __init__(self, master):
        self.master = master
        self.send_flag = False
        self.last_a = ''
        self.fig = None
        self.client_socket = None

        self.open_window_button = tk.Button(master, text="聊天记录", command=self.open_window)
        self.open_window_button.pack()
        self.open_window_button = tk.Button(master, text="聊天界面", command=self.open_window2)
        self.open_window_button.pack()
        self.open_window_button = tk.Button(master, text="函数图形", command=self.open_window3)
        self.open_window_button.pack()
    def open_window(self):
        # 创建连接和游标对象
        DB_FILE = "chat2.db"
        conn = sqlite3.connect(DB_FILE)
        c = conn.cursor()

        # 创建一个GUI窗口
        search_window = tk.Toplevel(self.master)
        search_window.title("Chat Database")
        search_window.geometry("1000x500")

        # 定义显示全部消息的函数
        def show_all_messages():
            # 执行SELECT命令
            c.execute('SELECT * FROM messages')
            results = c.fetchall()

            # 清空text框
            text.delete("1.0", tk.END)

            # 在text框中显示消息记录
            for row in results:
                text.insert(tk.END, f"ID: {row[0]}\n")
                text.insert(tk.END, f"Sender: {row[1]}\n")
                text.insert(tk.END, f"Receiver: {row[2]}\n")
                text.insert(tk.END, f"Message: {row[3]}\n")
                text.insert(tk.END, f"Time: {row[4]}\n\n")

        # 定义按关键字查找消息的函数
        def search_by_keyword(keyword):
            # 使用LIKE操作符进行模糊匹配
            c.execute("SELECT * FROM messages WHERE message LIKE ?", ('%'+keyword+'%',))
            results = c.fetchall()

            # 清空text框
            text.delete("1.0", tk.END)

            # 在text框中显示搜索结果
            for row in results:
                text.insert(tk.END, f"ID: {row[0]}\n")
                text.insert(tk.END, f"Sender: {row[1]}\n")
                text.insert(tk.END, f"Receiver: {row[2]}\n")
                text.insert(tk.END, f"Message: {row[3]}\n")
                text.insert(tk.END, f"Time: {row[4]}\n\n")

        # 定义按时间查找消息的函数
        def search_by_time(start_date, end_date):
            # 构造时间字符串
            start_time = start_date + " 00:00:00"
            end_time = end_date + " 23:59:59"

            # 执行SELECT命令
            c.execute("SELECT * FROM messages WHERE timestamp BETWEEN ? AND ?", (start_time, end_time))
            results = c.fetchall()

            # 清空text框
            text.delete("1.0", tk.END)

            # 在text框中显示搜索结果
            for row in results:
                text.insert(tk.END, f"ID: {row[0]}\n")
                text.insert(tk.END, f"Sender: {row[1]}\n")
                text.insert(tk.END, f"Receiver: {row[2]}\n")
                text.insert(tk.END, f"Message: {row[3]}\n")
                text.insert(tk.END, f"Time: {row[4]}\n\n")
        
        # 定义显示搜索窗口的函数
        def show_search_window():
            # 创建新窗口
            search_window = tk.Toplevel(self.master)
            search_window.title("Search Messages")

            # 添加按关键字搜索的部分
            keyword_label = tk.Label(search_window, text="Keyword:")
            keyword_label.pack()
            keyword_entry = tk.Entry(search_window)
            keyword_entry.pack()
            keyword_button = tk.Button(search_window, text="Search by Keyword",
                                       command=lambda: search_by_keyword(keyword_entry.get()))
            keyword_button.pack()

            # 添加按时间搜索的部分
            time_label1 = tk.Label(search_window, text="Start Date (yyyy-mm-dd):")
            time_label1.pack()
            time_entry1 = tk.Entry(search_window)
            time_entry1.pack()
            time_label2 = tk.Label(search_window, text="End Date (yyyy-mm-dd):")
            time_label2.pack()
            time_entry2 = tk.Entry(search_window)
            time_entry2.pack()
            time_button = tk.Button(search_window, text="Search by Time",
                                    command=lambda: search_by_time(time_entry1.get(), time_entry2.get()))
            time_button.pack()
        
        # 定义删除消息的函数
        def delete_message():
            message_id = delete_entry.get()
            if not message_id:
        # 如果用户未输入任何内容,清空文本框并返回
                delete_entry.delete(0, 'end')
                return
            try:
                message_id = int(message_id)
            except ValueError:
        # 如果用户输入的值无法转换为整数,弹出错误提示框并返回
                messagebox.showerror('Error', 'Invalid message ID')
                delete_entry.delete(0, 'end')
                return

            # 删除消息记录
            c.execute("DELETE FROM messages WHERE id=?", (message_id,))
            conn.commit()

            # 在text框中显示删除成功提示
            text.delete("1.0", tk.END)
            text.insert(tk.END, f"Message with ID {message_id} deleted successfully.")

        # 添加按钮和text控件
        show_all_button = tk.Button(search_window, text="Show all messages", command=show_all_messages, width=20, height=2)
        show_all_button.place(x=700, y=20)

        search_button = tk.Button(search_window, text="Search messages", command=show_search_window, width=20, height=2)
        search_button.place(x=700, y=80)

        delete_label = tk.Label(search_window, text="Message ID to delete:")
        delete_label.place(x=700, y=140)
        delete_entry = tk.Entry(search_window, width=20)
        delete_entry.place(x=700, y=170)
        delete_button = tk.Button(search_window, text="Delete", command=delete_message, width=20, height=2)
        delete_button.place(x=700, y=210)

        text = tk.Text(search_window, width=60, height=30)
        text.place(x=20, y=20)

       
    def open_window2(self):
        # 查询 messages 表是否已经存在,不存在则创建
        conn = sqlite3.connect('chat2.db')
        c = conn.cursor()
        c.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='messages'")
        result = c.fetchone()
        if result is None:
            c.execute('''CREATE TABLE messages (id INTEGER PRIMARY KEY AUTOINCREMENT, sender TEXT, receiver TEXT, message TEXT, timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP)''')
            conn.commit()
        conn.close()

# 发送消息到服务端
        def send(clientsocket):
    # 建立数据库连接和游标对象
            with sqlite3.connect('chat2.db') as conn_send:
                c_send = conn_send.cursor()
                while True:
                    data = input_box.get()
                    if not data:
                        print('Closing connection')
                        break
            # 发送消息给服务端
                    clientsocket.send(data.encode())
            # 将消息保存到数据库中
                    sender = 'Client'
                    receiver = 'Server'
                    message = data
                    c_send.execute("INSERT INTO messages (sender, receiver, message) VALUES (?, ?, ?)", (sender, receiver, message))
                    conn_send.commit()
                    message_box.config(state=tk.NORMAL)
                    message_box.insert(tk.END, f"{sender}: {message}\n")
                    message_box.config(state=tk.DISABLED)
                    input_box.delete(0, tk.END)

        def receive_thread():
    # 初始化消息框内容
    # 查询数据库中的历史消息,并显示在消息显示区域中
            conn = sqlite3.connect('chat2.db')
            c = conn.cursor()
            c.execute('''SELECT sender, message FROM messages ORDER BY id DESC LIMIT 20''')
            rows = c.fetchall()
            rows.reverse()
            message_box.config(state=tk.NORMAL)
            for row in rows:
                message_box.insert(tk.END, f"{row[0]}: {row[1]}\n")
            message_box.config(state=tk.DISABLED)
            conn.close()
            message_box.config(state=tk.NORMAL)
            message_box.insert(tk.END, "等待消息...\n")
            message_box.config(state=tk.DISABLED)

    # 循环接收消息
            while True:
                try:
            # 接收数据
                    data = clientsocket.recv(1024)
                except ConnectionResetError:
                    print("连接已断开")
                    clientsocket.close()
                    break
                except ConnectionAbortedError:
                    print("连接已中止")
                    clientsocket.close()
                    break
                if not data:
                    print('Client disconnected')
                    break

        # 显示接收到的消息并保存到数据库中
                message = data.decode()
                print('Received from server:', message)

        # 在消息框中显示消息
                message_box.config(state=tk.NORMAL)
                message_box.insert(tk.END, f"Sever: {message}\n")
                message_box.config(state=tk.DISABLED)

        # 将消息保存到数据库中
                conn_recv = sqlite3.connect('chat2.db')
                c_recv = conn_recv.cursor()
                sender = 'Client'
                receiver = 'Server'
                c_recv.execute("INSERT INTO messages (sender, receiver, message) VALUES (?, ?, ?)", (sender, receiver, message))
                conn_recv.commit()
                conn_recv.close()

    # 关闭连接
            try:
                if input_box.winfo_exists():
                    input_box.config(state=tk.DISABLED)
            except tk.TclError:
                pass
            try:
                if send_button.winfo_exists():
                    send_button.config(state=tk.DISABLED)
            except tk.TclError:
                pass
            clientsocket.close()

        def start_send_thread():
            threading.Thread(target=send, args=(clientsocket,)).start()

# 创建图形界面
        root = tk.Tk()
        root.title("Chat Client")

# 输入消息
        input_label = tk.Label(root, text="Message:")
        input_label.pack(side=tk.LEFT)
        input_box = tk.Entry(root)
        input_box.pack(side=tk.LEFT)

# 发送按钮
        send_button = tk.Button(root, text='Send', font=('Arial', 12), width=5, command=start_send_thread)
        send_button.pack(side=tk.LEFT)

# 消息显示区域
        message_scrollbar = tk.Scrollbar(root)
        message_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        message_box = tk.Text(root, state=tk.DISABLED)
        message_box.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)
        message_scrollbar.config(command=message_box.yview)
        message_box.config(yscrollcommand=message_scrollbar.set)

# 创建 socket 对象并连接服务器
        clientsocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        clientsocket.connect(('127.0.0.1',8000))
        print('Connected to server')

# 启动发送和接收线程
        send_thread = threading.Thread(target=send, args=(clientsocket,))
        receive_thread = threading.Thread(target=receive_thread)
        send_thread.start()
        receive_thread.start()

# 关闭连接和数据库连接
        root.protocol("WM_DELETE_WINDOW", lambda: [clientsocket.close(), conn.close(), root.destroy()])
        root.mainloop()

# 等待发送和接收线程结束
        send_thread.join()
        receive_thread.join()


    def close_db(self):
    
        self.conn.close()
        self.clientsocket.close()
        self.serversocket.close()
    def open_window3(self):
        def send():
            while True:
                if self.send_flag:
                    a = fn_entry.get()
                    if a != self.last_a:
                        self.client_socket.send(a.encode())
                        self.last_a = a
                    self.send_flag = False
                time.sleep(0.1)


        def start_send_thread():
            threading.Thread(target=send).start()


        def receive_and_draw_graph():
            while True:
                try:
                    a = self.client_socket.recv(1024).decode('utf-8')
                    if not a:
                        self.client_socket.close()
                        break
                    root.after(100, lambda: draw_graph(a))
                except ConnectionResetError:
                    self.client_socket.close()
                    break
                except ConnectionAbortedError:
                    print("服务器已关闭连接!")
                    self.client_socket.close()
                    break


        def draw_graph(a=None):
            if a is None:
                a = fn_entry.get()

            x = np.linspace(-10, 10, 1000)
            try:
                y = eval(str(a))
            except:
                error_label.config(text="输入函数有误!!!")
                return

            if self.fig is None:
                self.fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(6, 8))
                self.fig.canvas.set_window_title("函数图像")

                ax1.plot(x, y, label="f(x)", color='red')
                ax1.set_xlabel("X")
                ax1.set_ylabel("Y")
                ax1.legend()

                plot_derivative(a, ax2)
                ax2.set_xlabel("X")
                ax2.set_ylabel("Y")
                ax2.legend()

                canvas = FigureCanvasTkAgg(self.fig, master=root)
                canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
                self.fig.canvas.draw_idle()
            else:
                ax1, ax2 = self.fig.get_axes()
                ax1.lines[0].set_data(x, y)
                plot_derivative(a, ax2)
                self.fig.canvas.draw_idle()


        def plot_derivative(f, ax, x_range=(-10, 10)):
            x = np.linspace(x_range[0], x_range[1], 1000)
            try:
                dy = np.gradient(eval(f), x)
                ax.clear()
                ax.plot(x, dy, linewidth=1, color='pink', label="f'(x)")
                ax.legend()
            except:
                error_label.config(text="无法绘制导函数图像!!!")


        root = tk.Tk()
        root.title("函数图像")

        input_frame = tk.Frame(root)
        input_frame.pack()

        fn_label = tk.Label(input_frame, text="函数:")
        fn_label.pack(side=tk.LEFT)

        fn_entry = tk.Entry(input_frame)
        fn_entry.pack(side=tk.LEFT)

        error_label = tk.Label(root, fg="red")
        error_label.pack()

        button = tk.Button(root, text="确定", command=lambda: [draw_graph(), send_data()])
        button.pack()


        def send_data():
            self.send_flag = True


        clientsocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        clientsocket.connect(('127.0.0.1',8001))
        print('Connected to server')

        self.client_socket = clientsocket

        start_send_thread()

        receive_thread = threading.Thread(target=receive_and_draw_graph)
        receive_thread.start()

        root.protocol("WM_DELETE_WINDOW", lambda: [self.client_socket.close(), root.destroy()])

        root.mainloop()

        receive_thread.join()
if __name__ == '__main__':
    root = tk.Tk()
    app = App(root)
    root.mainloop()

这段代码在我运行后点击函数图形后会出现两个问题,第一个是输入函数方程后点击确认,所有的图形化界面会缩小;第二个问题是,在启用函数图像这个功能并关闭后,再关闭主界面后,程序运行并不会暂停,而是持续运行,然后就是如果不点函数图像这个功能然后关闭所有界面,程序可以正常结束运行,这两个问题该如何解决。

img

img

img


第一张图片是我那个所有界面都关了以后就是这样的,然后变小的照片,但是我在jupyter上运行是一切正常的

哼,能有多长

~~~~打扰了