在创建应用程序变量后将其传递给线程,而不是在线程创建过程中尝试传递,因为操作顺序的原因,这是不起作用的。
使用锁确保主线程和数据线程都能安全地访问和修改应用程序变量。
这是修改后的代码:
import tkinter as tk
import socket
import sys
from tkinter.simpledialog import askstring
from tkinter import *
from tkinter import messagebox
import time
import threading
import protocol
IP = "127.0.0.1"
PORT = 1234
BIG_BUFFER = 256
stop_event = threading.Event()
logged_in = False
def packed(cmd):
return cmd.encode()
def receive_data_from_server(client, app):
while not stop_event.isSet():
try:
server_cmd = client.recv(BIG_BUFFER).decode()
if server_cmd:
print(server_cmd)
if protocol.check_cmd(server_cmd):
app.handle_server_response(server_cmd)
else:
print("invalid cmd: " + server_cmd)
except Exception as err:
print(err)
class LogInWindow(tk.Tk):
def __init__(self, client, *args, **kwargs):
super().__init__(*args, **kwargs)
self.lock = threading.Lock()
self.client = client
self.title("Log In")
self.geometry("500x400")
self.protocol("WM_DELETE_WINDOW", self.on_closing)
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(1, weight=1)
self.frames = {}
for F in (LoginPage, RegisterPage):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=1, sticky="nsew")
self.show_frame(LoginPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
def login_successful(self):
self.destroy()
global logged_in
logged_in = True
def on_closing(self):
if messagebox.askokcancel("Quit", "Do you want to close the application?"):
self.client.send(packed("exit"))
stop_event.set()
self.destroy()
def send(self, msg):
self.client.send(packed(msg))
class LoginPage(tk.Frame):
def __init__(self, parent, controller):
super().__init__(parent)
self.controller = controller
label = tk.Label(self, text="Login Page", font=("Helvetica", 18))
label.pack(pady=10, padx=10)
username_label = tk.Label(self, text="Username:")
username_label.pack()
self.username_entry = tk.Entry(self)
self.username_entry.pack()
password_label = tk.Label(self, text="Password:")
password_label.pack()
self.password_entry = tk.Entry(self, show="*")
self.password_entry.pack()
login_button = tk.Button(self, text="Login", command=self.login)
login_button.pack(pady=5)
register_button = tk.Button(self, text="Register", command=lambda: controller.show_frame(RegisterPage))
register_button.pack(pady=5)
self.error_label = tk.Label(self, text="", fg="red")
self.error_label.pack(pady=5)
def login(self):
username = self.username_entry.get()
password = self.password_entry.get()
self.controller.send("log_in-" + username + "-" + password)
if username == "user" and password == "password":
self.controller.login_successful()
else:
self.error_label.config(text="Invalid username or password")
def main():
try:
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((IP, PORT))
except Exception as error:
print(error)
app = LogInWindow(client)
data_thread = threading.Thread(target=receive_data_from_server, args=(client, app))
data_thread.daemon = True
data_thread.start()
app.mainloop()
stop_event.set()
data_thread.join()
client.close()
if __name__ == "__main__":
main()
通过这种方式,在应用程序对象完全初始化后,将应用程序变量传递给receive_data_from_server线程。此外,锁用于确保从主线程和数据线程安全访问应用程序变量。