简介
使用Python编写的基于socket UDP通信的多功能即时聊天室,包含Tkinter编写的图形化聊天界面,功能包括有账号注册和登录,登录成功后可以查看在线用户,并和聊天室内的其他在线用户聊天,包含私聊和群发,能发送文字、表情包,以及文件等。
功能
- 登录和注册
- 显示在线用户
- 群聊和私聊
- 发送文字消息和表情包
- 发送文件
- 其他功能可自行添加
界面演示
(1)登录界面
(2)注册界面
(3)聊天界面
部分源代码
(1)登录界面源代码
import randomimport sqlite3from tkinter import *from tkinter import messageboxfrom PIL import Image, ImageTkfrom need_module import json,ctypes,sys,osclass Login(object):def __init__(self, Register,Chat,master=None):self.root = master# 定义内部变量rootself.root.title('登录窗口')self.Register=Registerself.Chat=Chatself.root.iconbitmap(r'images/icon/login.ico')# 设置左上角窗口图标# 设置窗口居中sw = self.root.winfo_screenwidth()# 计算水平距离sh = self.root.winfo_screenheight()# 计算垂直距离w = 690# 宽h = 535# 高x = (sw - w) / 2y = (sh - h) / 2self.root.geometry("%dx%d+%d+%d" % (w, h, (x + 160), y))self.root.resizable(0, 0)# 窗口设置为不可放大缩小# 告诉操作系统使用程序自身的dpi适配ctypes.windll.shcore.SetProcessDpiAwareness(1)# 获取屏幕的缩放因子ScaleFactor = ctypes.windll.shcore.GetScaleFactorForDevice(0)# 设置程序缩放self.root.tk.call('tk', 'scaling', ScaleFactor / 75)self.creatlogin()def creatlogin(self):self.fr2 = Frame(self.root)self.fr2.pack()self.fr1 = Frame(self.root)self.fr1.pack(pady=10)self.benner_list = ['images/benner/banner-1.jpg', 'images/benner/banner-2.jpg', 'images/benner/banner-3.jpg','images/benner/banner-4.jpg', 'images/benner/banner-5.jpg', 'images/benner/banner-6.jpg', ]self.benner_img = random.choice(self.benner_list)# 随机一张背景图# 图片大小:690x300self.pic = Image.open(self.benner_img)self.login_benner = ImageTk.PhotoImage(self.pic)# 标签 图片self.imgLabel = Label(self.fr2, image=self.login_benner)self.imgLabel.pack()# 标签 用户和密码self.label_usr = Label(self.fr1, text="用户名:")self.label_usr.grid(row=0, column=0, pady=10)self.label_pwd = Label(self.fr1, text="密码:")self.label_pwd.grid(row=1, column=0)# 文本框 用户名self.var_usr_name = StringVar()self.entry_name = Entry(self.fr1, textvariable=self.var_usr_name)self.entry_name.grid(row=0, column=1)self.entry_name.focus_set()# 获得焦点# 文本框 密码self.var_usr_pwd = StringVar()self.entry_pwd = Entry(self.fr1, textvariable=self.var_usr_pwd, show="*")self.entry_pwd.grid(row=1, column=1)self.saved_msg()self.fr3 = Frame(self.root)self.fr3.pack()self.rd_login = IntVar()self.rd_Passwd = IntVar()self.checkboxLogin = Checkbutton(self.fr3, text="自动登录", variable=self.rd_login)self.checkboxPasswd = Checkbutton(self.fr3, text="记住密码", variable=self.rd_Passwd)self.la = Label(self.fr3, width=5)self.la.grid(row=0, column=0)self.checkboxLogin.grid(row=0, column=1)self.checkboxPasswd.grid(row=0, column=2)# 登录self.root.bind('', self.check_login)# 绑定回车键self.bt_login = Button(self.fr3, text=" 登录 ", command=lambda: self.check_login())self.bt_login.grid(row=1, column=1, pady=5)self.bt_quit = Button(self.fr3, text=" 退出 ", command=sys.exit)self.bt_quit.grid(row=1, column=2)# # 底部标签self.fr4 = Frame(self.root)self.fr4.pack(side='bottom')self.bt_register = Button(self.fr4, text=" 注册账号", relief=FLAT, bg='#f0f0f0', command=self.login_win_close)self.bt_register.pack(side='left', anchor='s')self.la2 = Label(self.fr4, width=150)self.la2.pack()self.tsLabel2 = Label(self.fr4, text="聊天登录界面 by LGH ", fg="red")self.tsLabel2.pack(side='right', anchor='s', pady=5)def red_msg(self):if self.rd_Passwd.get() == 1:# 创建新的JSONnew_usr = {'username': self.var_usr_name.get(),'password': self.var_usr_pwd.get()}with open('usr.json', 'w') as wp:json.dump(new_usr, wp)def saved_msg(self):self.saved_name = ''self.saved_pwd = ''if os.path.exists('usr.json'):with open('usr.json', 'r') as fp:json_file = json.load(fp)json_str = json.dumps(json_file)json_date = json.loads(json_str)print(json_date)self.saved_name = json_date['username']self.saved_pwd = json_date['password']# print(self.saved_name,self.saved_pwd)if self.saved_name != '':self.entry_name.insert(END, self.saved_name)self.entry_pwd.insert(END, self.saved_pwd)def login_win_close(self):self.fr1.destroy()self.fr2.destroy()self.fr3.destroy()self.fr4.destroy()# 登录界面卸载self.Register(Login,self.Chat,self.root)# 密码对,就把主窗体模块的界面加载def check_login(self, *args):global usr_nameself.usr_name = self.var_usr_name.get()self.usr_pwd = self.var_usr_pwd.get()conn = sqlite3.connect('yonghu.db')cursor = conn.cursor()if self.usr_name == '' or self.usr_pwd == '':messagebox.showwarning(title='提示', message="用户名密码不能为空")else:# 执行查询语句:cursor.execute('select username from user')values = cursor.fetchall()cursor.execute('select password from user where username="%s"' % self.usr_name)# 获得查询结果集:values2 = cursor.fetchall()userList = []for i in values:# print(i[0])userList.append(i[0])if self.usr_name in userList:if self.usr_pwd == values2[0][0]:messagebox.showinfo(title='提示', message='登录成功,欢迎回来!')self.root.unbind('')# 解绑回车键事件self.red_msg()print('是否记住密码:',self.rd_Passwd.get())self.fr1.destroy()self.fr2.destroy()self.fr3.destroy()self.fr4.destroy()# 登录界面卸载self.Chat(self.usr_name)else:messagebox.showerror(title='提示', message="用户名密码错误!")else:messagebox.showerror(title='提示', message="没有该用户名!")cursor.close()conn.close()# 下面返回字符串break使回车绑定事件只触发绑定的方法而不进行默认的换行操作return 'break'
(2)注册界面源代码
import randomimport sqlite3from tkinter import *from tkinter import messageboxfrom PIL import Image, ImageTkfrom need_module import sysclass Register(object):def __init__(self, Login,Chat,master=None):self.root = master# 定义内部变量rootself.root.title('注册窗口')self.Login=Loginself.Chat=Chat# 设置窗口居中sw = self.root.winfo_screenwidth()# 计算水平距离sh = self.root.winfo_screenheight()# 计算垂直距离w = 690# 宽h = 520# 高x = (sw - w) / 2y = (sh - h) / 2self.root.geometry("%dx%d+%d+%d" % (w, h, (x + 160), y))self.root.iconbitmap(r'images/icon/register.ico')# 设置左上角窗口图标self.root.resizable(0, 0)# 窗口设置为不可放大缩小# # 告诉操作系统使用程序自身的dpi适配# ctypes.windll.shcore.SetProcessDpiAwareness(1)# # 获取屏幕的缩放因子# ScaleFactor = ctypes.windll.shcore.GetScaleFactorForDevice(0)# # 设置程序缩放# self.root.tk.call('tk', 'scaling', ScaleFactor / 75)self.creatregister()def creatregister(self):self.fr2 = Frame(self.root)self.fr2.pack()self.fr1 = Frame(self.root)self.fr1.pack(pady=10)self.benner_list = ['images/benner/banner-1.jpg', 'images/benner/banner-2.jpg', 'images/benner/banner-3.jpg','images/benner/banner-4.jpg', 'images/benner/banner-5.jpg', 'images/benner/banner-6.jpg', ]self.benner_img = random.choice(self.benner_list)# 随机一张背景图# 图片大小:690x300self.pic = Image.open(self.benner_img)self.register_benner = ImageTk.PhotoImage(self.pic)# 标签 图片self.imgLabel = Label(self.fr2, image=self.register_benner)self.imgLabel.pack()# 标签 用户和密码self.label_usr = Label(self.fr1, text="用户名:")self.label_usr.grid(row=0, column=0)self.label_pwd = Label(self.fr1, text="密码:")self.label_pwd.grid(row=1, column=0, pady=5)self.label_repwd = Label(self.fr1, text="确认密码:")self.label_repwd.grid(row=2, column=0)# 文本框 用户名self.var_usr_name = StringVar()self.entry_name = Entry(self.fr1, textvariable=self.var_usr_name)self.entry_name.grid(row=0, column=1)self.entry_name.focus_set()# 获得焦点self.docheck1 = self.entry_name.register(self.usercheck)# 自带验证功能,usercheck自定义函数self.entry_name.config(validate='all', validatecommand=(self.docheck1, '%P'))# 文本框 密码self.var_usr_pwd = StringVar()self.entry_pwd = Entry(self.fr1, textvariable=self.var_usr_pwd, show="*")self.entry_pwd.grid(row=1, column=1)self.docheck2 = self.entry_pwd.register(self.passwordcheck)self.entry_pwd.config(validate='all', validatecommand=(self.docheck2, '%d', '%S'))# 文本框 确认密码self.var_usr_repwd = StringVar()self.entry_repwd = Entry(self.fr1, textvariable=self.var_usr_repwd, show="*")self.entry_repwd.grid(row=2, column=1)self.fr3 = Frame(self.root)self.fr3.pack()# 登录self.root.bind('', self.reg)# 绑定回车键self.bt_register = Button(self.fr3, text=" 注册 ", command=lambda: self.reg())self.bt_register.grid(row=1, column=1, pady=5, padx=35)# self.la = Label(self.fr3, width=5)# self.la.grid(row=0, column=0)self.bt_quit = Button(self.fr3, text=" 退出 ", command=sys.exit)self.bt_quit.grid(row=1, column=2)# # 底部标签self.fr4 = Frame(self.root)self.fr4.pack(side='bottom')self.bt_register = Button(self.fr4, text=" 返回登录", relief=FLAT, bg='#f0f0f0', command=self.register_win_close)self.bt_register.pack(side='left', anchor='s')self.la2 = Label(self.fr4, width=150)self.la2.pack()self.tsLabel2 = Label(self.fr4, text="用户注册界面 by LGH ", fg="red")self.tsLabel2.pack(side='right', anchor='s', pady=5)def register_win_close(self):self.fr1.destroy()self.fr2.destroy()self.fr3.destroy()self.fr4.destroy()# 登录界面卸载self.Login(Register,self.Chat,self.root)# 密码对,就把主窗体模块的界面加载def usercheck(self, what):if len(what) > 8:self.la2.config(text='用户名不能超过8个字符', fg='red')return Falsereturn Truedef passwordcheck(self, why, what):if why == '1':if what not in '0123456789':self.la2.config(text='密码只能是数字', fg='red')return Falsereturn Truedef reg(self, *args):usr_name = self.var_usr_name.get()usr_pwd = self.var_usr_pwd.get()usr_repwd = self.var_usr_repwd.get()if usr_name == '' or usr_pwd == '' or usr_repwd == '':messagebox.showwarning(title='提示', message="用户名密码不能为空")else:# 如果文件不存在,会自动在当前目录创建:conn = sqlite3.connect('yonghu.db')# 创建一个Cursor:cursor = conn.cursor()# 执行一条SQL语句,创建user表:cursor.execute('create table if not exists user(username varchar(20),password varchar(20))')# 查询用户名是否存在cursor.execute('select username from user')values = cursor.fetchall()userList = []for i in values:# print(i[0])userList.append(i[0])if usr_name in userList:messagebox.showwarning('提示', '用户名已存在!')else:if usr_pwd == usr_repwd:# 插入数据cursor.execute("insert into user (username,password) values (" />')# 解绑回车键事件self.register_win_close()else:messagebox.showerror('提示', '两次输入的密码不一致!')# 关闭Cursor:cursor.close()# 提交事务:conn.commit()# 关闭Connection:conn.close()# 下面返回字符串break使回车绑定事件只触发绑定的方法而不进行默认的换行操作return 'break'
因为代码太多我就不直接贴出来了,项目完整源代码上传到我的Github仓库了,可自行下载。下载后安装代码里用到的第三方库,就可直接正常运行项目。
代码地址:https://github.com/ihmily/Python-ChatRoom
注意:先运行服务器端server.py,再运行客户端client.py