forked from 2044-space-elevator/TouchFish
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclient.py
More file actions
227 lines (187 loc) · 7.96 KB
/
client.py
File metadata and controls
227 lines (187 loc) · 7.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
import tkinter as tk
import socket
import threading
import platform
import sys
from tkinter import messagebox
class ChatClient:
def __init__(self):
self.root = tk.Tk()
self.root.title("聊天客户端")
self.font_family = ("微软雅黑", 12)
self.bell_enabled = False
self.create_connection_window()
self.root.mainloop()
def create_connection_window(self):
"""创建连接窗口"""
frame = tk.Frame(self.root, padx=20, pady=20)
frame.pack()
# 服务器地址
tk.Label(frame, text="服务器IP:").grid(row=0, column=0, sticky="w")
self.ip_entry = tk.Entry(frame, width=20)
self.ip_entry.grid(row=0, column=1, pady=5)
self.ip_entry.insert(0, "127.0.0.1")
# 端口
tk.Label(frame, text="端口:").grid(row=1, column=0, sticky="w")
self.port_entry = tk.Entry(frame, width=10)
self.port_entry.grid(row=1, column=1, pady=5, sticky="w")
self.port_entry.insert(0, "8080")
# 用户名
tk.Label(frame, text="用户名:").grid(row=2, column=0, sticky="w")
self.user_entry = tk.Entry(frame, width=20)
self.user_entry.grid(row=2, column=1, pady=5)
# 连接按钮
connect_btn = tk.Button(frame, text="连接", command=self.connect_to_server)
connect_btn.grid(row=3, columnspan=2, pady=10)
# 提示
tk.Label(frame, text="提示: Ctrl+Enter 发送消息").grid(row=4, columnspan=2)
def connect_to_server(self):
"""连接到服务器"""
try:
self.server_ip = self.ip_entry.get()
self.port = int(self.port_entry.get())
self.username = self.user_entry.get()
if not self.username:
messagebox.showerror("错误", "用户名不能为空")
return
self.socket = socket.socket()
self.socket.connect((self.server_ip, self.port))
self.root.destroy() # 关闭连接窗口
self.create_chat_window() # 打开聊天窗口
# 启动消息接收线程
threading.Thread(target=self.receive_messages, daemon=True).start()
# self.receive_messages()
self.chat_win.mainloop()
except Exception as e:
messagebox.showerror("连接错误", f"无法连接到服务器:\n{str(e)}")
def create_chat_window(self):
"""创建聊天窗口"""
self.chat_win = tk.Tk()
self.chat_win.title(f"聊天室 - {self.username}")
self.chat_win.geometry(f"600x400")
# 聊天记录框
self.chat_frame = tk.Frame(self.chat_win)
self.chat_frame.pack(fill="both", expand=True, padx=10, pady=10)
scrollbar = tk.Scrollbar(self.chat_frame)
scrollbar.pack(side="right", fill="y")
self.chat_text = tk.Text(
self.chat_frame,
yscrollcommand=scrollbar.set,
font=self.font_family,
state="disabled"
)
self.chat_text.pack(fill="both", expand=True)
scrollbar.config(command=self.chat_text.yview)
# 消息输入框
input_frame = tk.Frame(self.chat_win)
input_frame.pack(fill="x", padx=10, pady=5)
self.msg_entry = tk.Text(
input_frame,
height=3,
font=self.font_family
)
self.msg_entry.pack(side="left", fill="x", expand=True, padx=(0, 5))
self.msg_entry.bind("<Control-Return>", lambda e: self.send_message())
# 发送按钮
send_btn = tk.Button(input_frame, text="发送", command=self.send_message)
send_btn.pack(side="right")
# 设置按钮
setting_btn = tk.Button(self.chat_win, text="设置", command=self.open_settings)
setting_btn.pack(side="bottom", pady=5)
def open_settings(self):
"""打开设置窗口"""
settings_win = tk.Toplevel(self.chat_win)
settings_win.title("设置")
settings_win.transient(self.chat_win)
settings_win.grab_set()
# 字体设置
font_frame = tk.LabelFrame(settings_win, text="字体设置", padx=10, pady=10)
font_frame.pack(padx=10, pady=5, fill="x")
tk.Label(font_frame, text="字体名称:").grid(row=0, column=0, sticky="w")
font_name_entry = tk.Entry(font_frame)
font_name_entry.grid(row=0, column=1, padx=5, pady=2)
font_name_entry.insert(0, self.font_family[0])
tk.Label(font_frame, text="字体大小:").grid(row=1, column=0, sticky="w")
font_size_entry = tk.Entry(font_frame)
font_size_entry.grid(row=1, column=1, padx=5, pady=2)
font_size_entry.insert(0, str(self.font_family[1]))
# 提示音设置
bell_frame = tk.LabelFrame(settings_win, text="提示音设置", padx=10, pady=10)
bell_frame.pack(padx=10, pady=5, fill="x")
bell_var = tk.BooleanVar(value=self.bell_enabled)
bell_check = tk.Checkbutton(
bell_frame,
text="启用消息提示音",
variable=bell_var,
state="normal" if platform.system() == "Windows" else "disabled"
)
bell_check.pack(anchor="w")
# 确定按钮
def apply_settings():
try:
font_name = font_name_entry.get()
font_size = int(font_size_entry.get())
self.font_family = (font_name, font_size)
self.bell_enabled = bell_var.get()
self.chat_text.config(font=self.font_family)
settings_win.destroy()
except ValueError:
messagebox.showerror("错误", "字体大小必须是整数")
tk.Button(
settings_win,
text="确定",
command=apply_settings
).pack(pady=10)
def send_message(self):
"""发送消息"""
message = self.msg_entry.get("1.0", "end").strip()
if not message:
return
full_msg = f"{self.username}: {message}\n"
try:
self.socket.send(full_msg.encode("utf-8"))
self.msg_entry.delete("1.0", "end")
except Exception as e:
messagebox.showerror("发送错误", f"消息发送失败:\n{str(e)}")
def receive_messages(self):
"""接收消息的线程函数"""
while True:
try:
message = self.socket.recv(1024).decode("utf-8")
# 在GUI线程更新界面
self.chat_win.after(0, self.display_message, message)
# 播放提示音
if self.bell_enabled and not message.startswith(f"{self.username}:"):
self.play_notification_sound()
except Exception as e:
break
def display_message(self, message):
"""在聊天框中显示消息"""
self.chat_text.config(state="normal")
self.chat_text.insert("end", message)
self.chat_text.see("end")
self.chat_text.config(state="disabled")
def play_notification_sound(self):
"""播放提示音(跨平台)"""
try:
if platform.system() == "Windows":
import winsound
winsound.Beep(1000, 200)
elif platform.system() == "Darwin": # macOS
import os
os.system("afplay /System/Library/Sounds/Ping.aiff&")
else: # Linux
import os
os.system("paplay /usr/share/sounds/freedesktop/stereo/message.oga&")
except:
pass
def on_closing(self):
"""关闭窗口时的处理"""
try:
self.socket.close()
except:
pass
self.chat_win.destroy()
sys.exit()
if __name__ == "__main__":
ChatClient()