python 簡易微信實現(註冊登入+資料庫儲存+聊天+GUI+檔案傳輸)
python socket+tkinter詳解+簡易微信實現
歷經多天的努力,查閱了許多大佬的部落格後終於實現了一個簡易的微信O(∩_∩)O~~
簡易資料庫的實現
使用pands+CSV實現資料庫框架搭建
import socket
import threading
from pandas import *
import pymysql
import csv
# 建立DataFrame物件
# 儲存使用者資料的表(狀態沒用上。。。)
df = pandas.DataFrame([['whs','123','1']], columns=['account','password','state'], index=[0])
df.to_csv('user.csv',index=0)
#儲存好友關係
df = pandas.DataFrame([['whs','wyl']], columns=['friend1','friend2'], index=[0])
df.to_csv('link.csv',index=0)
#儲存待新增好友關係的表
df = pandas.DataFrame([['whs','@@@']], columns=['friend1','friend2'], index=[0])
df.to_csv('to_be_link.csv',index=0)
#儲存線上人
df = pandas.DataFrame([['whs','127.0.0.1']], columns=['name','addr'], index=[0])
df.to_csv('onlinelist.csv',index=0)
#在客戶端用於儲存最近收到的資訊
df = pandas.DataFrame([['@@@','@@@','@@@']], columns=['name','title','message'], index=[0])
df.to_csv('resent_message.csv',index=0)
print(df)
通過對csv表的操作實現對好友操作
新增線上人
def addonlinelist(name,addr,connectionSocket):
onlinelist = read_csv('onlinelist.csv', dtype={'name': str,'addr': str})
#開啟csv檔案並指定格式
flag = onlinelist[onlinelist.name == name].shape[0]
#如果資料不存在
if(flag!=0):
k = onlinelist[onlinelist.name == name].index.tolist()[0]
onlinelist=onlinelist.drop(k)
#如果有之前的殘餘資料則刪去
connect_list.append(connectclient(name,addr,connectionSocket))
new = DataFrame({'name': name, 'addr': str(addr)},index=[0])
onlinelist = onlinelist.append(new,ignore_index=True)
#儲存,並且忽略index
onlinelist.to_csv('onlinelist.csv',index=0)
對使用者登入的檢驗
語法與之前幾乎一樣,不做贅述
def adduser(name,passwd,status):#新增使用者
user = read_csv('user.csv', dtype={'name': str,'passwd': str})
flag = user[user.name == name].shape[0]
if(flag != 0):
return False
new = DataFrame({'name': name, 'passwd': passwd, 'status': status}, index=[0])
user = user.append(new, ignore_index=True)
user.to_csv('user.csv',index=0)
return True
def checkexist(name):#檢視使用者是否存在
user = read_csv('user.csv', dtype={'name': str,'passwd': str})
flag = user[user.name==name].shape[0]
if(flag==0):
return False
else:
return True
def checkuser(name,passwd):#檢視使用者名稱密碼正確性
user = read_csv('user.csv', dtype={'name': str,'passwd': str})
if(passwd==str(user[user.name == name].passwd.tolist()[0])):
return True
else:
return False
對使用者刪除新增好友接受好友請求
def deletefriend(name1,name2):#刪除好友
link = read_csv('link.csv', dtype={'friend1': str,'friend2': str})
flag = link[((link.friend1 == name1) & (link.friend2 == name2)) | ((link.friend1 == name2) & (link.friend2 == name1))].shape[0]
if(flag == 0):
return 'not_exist'
k = link[((link.friend1 == name1) & (link.friend2 == name2)) | ((link.friend1 == name2) & (link.friend2 == name1))].index.tolist()[0]
link = link.drop(k)
link.to_csv('link.csv', index=0)
return 'delete_ok'
def addfriend(name1,name2):#新增好友
if(isfriend(name1,name2)==True):
return 'already_friend'
to_be_link = read_csv('to_be_link.csv', dtype={'friend1': str,'friend2': str})
user = read_csv('user.csv')
flag = user[(user.name == name2)].shape[0]
if(flag == 0):
return 'not_exist'
new = DataFrame({'friend1':name1, 'friend2':name2}, index = [0])
to_be_link = to_be_link.append(new,ignore_index=True)
to_be_link.to_csv('to_be_link.csv',index=0)
return 'add_to_be'
def acceptfriend(name1,name2):#接收好友請求
link = read_csv('link.csv', dtype={'friend1': str,'friend2': str})
to_be_link = read_csv('to_be_link.csv', dtype={'friend1': str,'friend2': str})
print(type(name1))
print(type(name1))
if (istobefriend(name1, name2) == False):
return 'not_exist'
print('tttttttttt')
new = DataFrame({'friend1': name1, 'friend2': name2}, index=[0])
link = link.append(new, ignore_index=True)
link.to_csv('link.csv', index=0)
k = to_be_link[((to_be_link.friend1 == name1) & (to_be_link.friend2 == name2)) | ((to_be_link.friend1 == name2) & (to_be_link.friend2 == name1))].index.tolist()[0]
to_be_link = to_be_link.drop(k)
to_be_link.to_csv('to_be_link.csv',index=0)
# connectionSocket.send(('新增好友成功').encode())
return 'accept_ok'
def delete_to_be_friend(name1,name2):#從待接收列表中刪除
to_be_link = read_csv('to_be_link.csv', dtype={'friend1': str,'friend2': str})
k = to_be_link[((to_be_link.friend1 == name1) & (to_be_link.friend2 == name2)) | (
(to_be_link.friend1 == name2) & (to_be_link.friend2 == name1))].index.tolist()[0]
to_be_link = to_be_link.drop(k)
to_be_link.to_csv('to_be_link.csv', index=0)
def isfriend(name1,name2):#判斷兩個人是否是好友
link = read_csv('link.csv')
flag = link[((link.friend1 == name1) & (link.friend2 == name2)) | ((link.friend1 == name2) & (link.friend2 == name1))].shape[0]
if (flag == 0):
return False
return True
def istobefriend(name1,name2):#判斷是否發起好友請求
to_be_link = read_csv('to_be_link.csv', dtype={'friend1': str,'friend2': str})
flag = to_be_link[((to_be_link.friend1 == name1) & (to_be_link.friend2 == name2)) | (
(to_be_link.friend1 == name2) & (to_be_link.friend2 == name1))].shape[0]
if (flag == 0):
return False
return True
列印好友列表(待新增好友列表)
def printlist(name):#列印好友列表
link = read_csv('link.csv', dtype={'friend1': str,'friend2': str})
k = link[(link.friend1 == name)|(link.friend2 == name)].shape[0]
if(k==0):
return '.'
# connectionSocket.send(('您的好友列表如下').encode())
message = '/'.join(link[link.friend1 == name].friend2.tolist()+link[link.friend2 == name].friend1.tolist())
# connectionSocket.send(message.encode())
print(message)
return '/' + message
def printtobelist(name):#列印待同意好友列表
to_be_link = read_csv('to_be_link.csv', dtype={'friend1': str,'friend2': str})
k = to_be_link[(to_be_link.friend2 == name)].shape[0]
if (k == 0):
return '.'
# connectionSocket.send(('有如下的人要新增你為好友,想接受則輸入該好友名字,否則輸入/exit/退出').encode())
print(to_be_link[to_be_link.friend2 == name].friend1.tolist())
message = '/'.join(to_be_link[to_be_link.friend2 == name].friend1.tolist())
return '/'+message
socket+thread實現多執行緒通訊
通訊協議
'''
2.0 報頭
伺服器和客服端之間,使用自己定義的報頭進行通訊
協議整體大致呈樹形結構,收到訊息後進行一層層解析,得到最終的結果。
2.1 註冊
註冊傳送
root/reg/name/passwd
註冊接收
register_ok(註冊成功),register_error(使用者名稱以及存在)
2.2 登入
登入傳送
root/reg/name/passwd
登入接收
noPassword,user,noAccount
2.3 獲取好友列表
獲取已經有的好友的列表
root/friend_op(操作型別)/print_friend_list(操作方式)/myname
獲取向你提出好友申請的人的列表
root/friend_op(操作型別)/print_to_be_list(操作方式)/myname
2.4 新增好友
root/friend_op(操作型別)/add(操作方式)/myname/othername
伺服器端發出的資訊
root/friend_op/(delete)(add)/othername/state('not_exist''delete_ok''already_friend''not_exist''add_to_be')
使用者不存在 成功
2.5 好友請求回覆
root/friend_op(操作型別)/accept(操作方式)/myname/othername
2.6 刪除好友
root/friend_op(操作型別)/delete(操作方式)/myname/othername
2.7 [伺服器]好友請求
root/friend_op(操作型別)/add(操作方式)/othername
2.8 [伺服器]好友請求結果
root/friend_op/add/othername/state('not_exist''already_friend''add_to_be')
狀態分為分為該使用者不存在,你們已經是朋友,成功發出好友請求三種。
2.9 傳送訊息和檔案
從客服端傳輸資訊的格式
root/chat/message/from_name/to_name/message_content
客戶端傳送檔案的格式
root/chat/file/from_name/to_name
傳輸是否線上的系統訊息
2.10 [伺服器]訊息和檔案
root/chat/file/from_name/begin(end)
root/chat/message/to_name/message_content
2.11 離線
root/chat/info/system_message/from_name
(判斷是否線上後傳送)
'''
伺服器的連線
while True:
connectionSocket, addr = serverSocket.accept()
print(addr)
# connectionSocket.send(('連線主機成功').encode())
# 每當客戶端連線後啟動一個執行緒為該客戶端服務
threading.Thread(target=server_target, args=(connectionSocket, addr,)).start()
serverSocket.close()
客戶端的連線
if __name__ == '__main__':
t = Client()
main_login()
伺服器端對訊息的處理
def server_target(connectionSocket, addr):#伺服器主要函式
while(1):
message = connectionSocket.recv(1024).decode()
deal_message = message.split('/')
print(deal_message)
lenth = len(deal_message)
print(deal_message[0])
if(deal_message[0]=='un_root'):#收到則退出
connectionSocket.send(('un_root').encode())
break
else:
if(deal_message[1] == 'login'):#進行登入操作
account = deal_message[2]
password = deal_message[3]
if(checkexist(account)==False):
connectionSocket.send(('noAccount').encode())
elif(checkuser(account,password)==False):
connectionSocket.send(('noPassword').encode())
else:
connectionSocket.send(('user').encode())
addonlinelist(account, addr, connectionSocket)
elif(deal_message[1] == 'register'):#進行註冊
account = deal_message[2]
password = deal_message[3]
if(adduser(account, password, 1)):
connectionSocket.send(('register_ok').encode())
addonlinelist(account, addr, connectionSocket)
else:
connectionSocket.send(('register_error').encode())
elif(deal_message[1] == 'chat'):#進行資訊互動
type = deal_message[2]
account = deal_message[3]
friend_account = deal_message[4]
if(type == 'file'):
for clients in connect_list:
if (str(clients.name) == str(friend_account)):
print(('root/chat/' + type + '/' + account + '/begin'))
try:
clients.connectionSocket.send(
('root/chat/' + type + '/' + account + '/begin').encode())
except:
pass
# 申請相同大小的空間存放傳送過來的檔名與檔案大小資訊
fileinfo_size = struct.calcsize('128sl')
# 接收檔名與檔案大小資訊
buf = connectionSocket.recv(fileinfo_size)
for clients in connect_list:
if (str(clients.name) == str(friend_account)):
print(('root/chat/' + type + '/' + account + '/begin'))
try:
clients.connectionSocket.send(buf)
except:
pass
# 判斷是否接收到檔案頭資訊
if buf:
# 獲取檔名和檔案大小
filename, filesize = struct.unpack('128sl', buf)
fn = filename.strip(b'\00')
fn = fn.decode()
print ('file new name is {0}, filesize if {1}'.format(str(fn), filesize))
recvd_size = 0 # 定義已接收檔案的大小
# 儲存在該指令碼所在目錄下面
print ('start receiving...')
# 將分批次傳輸的二進位制流依次寫入到檔案
while not (recvd_size == filesize):
if filesize - recvd_size > 1024:
data = connectionSocket.recv(1024)
recvd_size += len(data)
else:
data = connectionSocket.recv(filesize - recvd_size)
recvd_size = filesize
for clients in connect_list:
if (str(clients.name) == str(friend_account)):
print(data)
try:
clients.connectionSocket.send(data)
except:
pass
print('end receive...')
elif(type == 'message'):
message = deal_message[5]+'/'+deal_message[6]
isfind = False
for clients in connect_list:#遍歷list傳送資訊
if(str(clients.name) == str(friend_account)):
print(('root/chat/' + type + '/' + account + '/' + message))
try:
clients.connectionSocket.send(('root/chat/'+type+'/'+account+'/'+ message).encode())
isfind = True
except:
pass
if(isfind == False):
connectionSocket.send(('root/chat/info/'+friend_account+'/'+'對方不線上無法接收你的訊息').encode())
# print(('root/chat/'+friend_account+'/'+account+'/'+'對方不線上無法接收你的訊息'))
elif(deal_message[1] == 'friend_op'):#對於好友命令進行操作
print(deal_message[2])
if(deal_message[2] == 'add'):
account = deal_message[3]
friend_account = deal_message[4]
connectionSocket.send(('root/friend_op/add/' + friend_account + '/' + addfriend(account, friend_account)).encode())
elif(deal_message[2] == 'accept'):
account = deal_message[3]
friend_account = deal_message[4]
acceptfriend(account, friend_account)
connectionSocket.send(('root/friend_op/accept/' + friend_account).encode())
elif(deal_message[2] == 'delete'):
account = deal_message[3]
friend_account = deal_message[4]
connectionSocket.send(('root/friend_op/delete/'+friend_account+'/'+deletefriend(account,friend_account)).encode())
elif(deal_message[2] == 'reject'):
account = deal_message[3]
friend_account = deal_message[4]
delete_to_be_friend(account,friend_account)
elif(deal_message[2] == 'print_friend_list'):
account = deal_message[3]
print(printlist(account))
connectionSocket.send((('root/friend_op/print_friend_list'+printlist(account)).strip('.')).encode())
print(('root/friend_op/print_friend_list'+printlist(account)).strip('.'))
elif(deal_message[2] == 'print_to_be_friend_list'):
account = deal_message[3]
connectionSocket.send((('root/friend_op/print_to_be_friend_list' + printtobelist(account)).strip('.')).encode())
print(('root/friend_op/print_to_be_frined_list' + printtobelist(account)).strip('.'))
客戶端對資訊的處理
class Client(object):
def __init__(self):
self.connecntsocket = socket(AF_INET, SOCK_STREAM)
self.connecntsocket.connect(('127.0.0.1', 12000))
#連線ip和埠
self.myqueue=queue.Queue()
self.name = ''
self.flag = True
self.friend_list = []
self.to_be_friend_list = []
def read_from_server(self):
while True:
if(self.flag==False):
break
message = self.connecntsocket.recv(1024).decode()
print(message)
deal_message = message.split('/')
print(deal_message)
lenth = len(deal_message)
print(deal_message[0])
if(deal_message[0] == 'un_root'):
break
else:
if(deal_message[1] == 'chat'):
if(deal_message[2] == 'message'):#處理資訊,放到該放的地方
print('message')
friend_account = deal_message[3]
friend_title = deal_message[4]
friend_message = deal_message[5]
resent_message = read_csv('resent_message.csv')
new = DataFrame({'name': friend_account, 'title': friend_title, 'message': friend_message}, index=[0])
resent_message = resent_message.append(new, ignore_index=True)
resent_message.to_csv('resent_message.csv', index=0)
isfind = False
for Chat_window in Chat_list:
if(Chat_window.name == friend_account):
try:
Chat_window.insert_message(friend_title,friend_message)
except:
pass
isfind = True
if(isfind == False):#to be continue
pass
elif(deal_message[2] == 'file'):
if(deal_message[4] == 'begin'):
# 申請相同大小的空間存放傳送過來的檔名與檔案大小資訊
fileinfo_size = struct.calcsize('128sl')
# 接收檔名與檔案大小資訊
buf = t.connecntsocket.recv(fileinfo_size)
# 判斷是否接收到檔案頭資訊
if buf:
# 獲取檔名和檔案大小
filename, filesize = struct.unpack('128sl', buf)
fn = filename.strip(b'\00')
fn = fn.decode()
print ('file new name is {0}, filesize if {1}'.format(str(fn), filesize))
recvd_size = 0 # 定義已接收檔案的大小
# 儲存在該指令碼所在目錄下面
fp = open('./' + str('new' + fn), 'wb')
print ('start receiving...')
# 將分批次傳輸的二進位制流依次寫入到檔案
while not recvd_size == filesize:
if filesize - recvd_size > 1024:
data = t.connecntsocket.recv(1024)
recvd_size += len(data)
else:
data = t.connecntsocket.recv(filesize - recvd_size)
recvd_size = filesize
fp.write(data)
fp.close()
print ('end receive...')
elif(deal_message[2] == 'info'):
friend_account = deal_message[3]
system_info = deal_message[4]
isfind = False
for Chat_window in Chat_list:
if (Chat_window.name == friend_account):
Chat_window.insert_info(system_info)
isfind = True
if (isfind == False):
pass
elif(deal_message[1] == 'friend_op'):
if(deal_message[2] == 'delete'):
if(deal_message[4] == 'not_exist'):
self.creatbox(deal_message[3] + '不在您的好友列表中')
elif(deal_message[4] == 'delete_ok'):
self.creatbox('已經把'+deal_message[3]+'從您的好友列表刪除')
elif(deal_message[2] == 'add'):
if(deal_message[4] == 'already_friend'):
self.creatbox('你和' + deal_message[3]+'已經是好友了')
elif(deal_message[4] == 'not_exist'):
self.creatbox('使用者' + deal_message[3] + '不存在')
elif(deal_message[4 == 'add_to_be']):
self.creatbox('已經傳送對'+deal_message[3]+'的好友申請')
elif(deal_message[2] == 'accept'):
self.creatbox('已經把' + deal_message[3] + '新增到您的好友列表')
elif(deal_message[2] == 'print_friend_list'):
self.friend_list = deal_message[3:lenth]
elif(deal_message[2] == 'print_to_be_friend_list'):
self.to_be_friend_list = deal_message[3:lenth]
print(1)
def creatbox(self,message):
tkinter.messagebox.showinfo(title='miniWechat', message=message)
def terminate(self):
self.flag = False
def run(self):
self.flag = True
self.THD = threading.Thread(target=self.read_from_server, args=()).start()
tkinter實現GUI
登入介面
class Login(object):
def __init__(self):
# 建立主視窗,用於容納其它元件
self.root = Tk()
# 給主視窗設定標題內容
self.root.title("miniWechat")
#自定義關閉按鈕,不然關閉GUI後socket還在執行中
self.root.protocol('WM_DELETE_WINDOW', self.my_close)
self.root.geometry('450x300')
#執行程式碼時記得新增一個gif圖片檔案,不然是會出錯的
self.canvas = tkinter.Canvas(self.root, height=300, width=500)#建立畫布
self.image_file = tkinter.PhotoImage(file='1572079024477.gif')
self.image = self.canvas.create_image(0,0, anchor='nw', image=self.image_file)#將圖片置於畫布上
self.canvas.grid(row=0, column=0)#放置畫布(為上端)
#建立一個`label`名為`Account: `
self.label_account = tkinter.Label(self.root, text='Account: ')
#建立一個`label`名為`Password: `
self.label_password = tkinter.Label(self.root, text='Password: ')
# 建立一個賬號輸入框,並設定尺寸
self.input_account = tkinter.Entry(self.root, width=30)
# 建立一個密碼輸入框,並設定尺寸
self.input_password = tkinter.Entry(self.root, show='*', width=30)
# 建立一個登入系統的按鈕
self.login_button = tkinter.Button(self.root, command = self.backstage_interface, text = "Login", width=10)
# 建立一個註冊系統的按鈕
self.siginUp_button = tkinter.Button(self.root, command = self.siginUp_interface, text = "Sign up", width=10)
# 完成佈局
def gui_arrang(self):
self.label_account.place(x=60, y= 170)
self.label_password.place(x=60, y= 195)
self.input_account.place(x=135, y=170)
self.input_password.place(x=135, y=195)
self.login_button.place(x=140, y=235)
self.siginUp_button.place(x=240, y=235)
# 進入註冊介面
def siginUp_interface(self):
# self.root.destroy()
account = self.input_account.get()
password = self.input_password.get()
verifyResult =self.reg_verifyAccountData(account,password)
if(verifyResult == 'register_ok'):
t.name = account
self.start()
else:
tkinter.messagebox.showinfo(title='註冊資訊提示', message='使用者名稱已經被使用')
# 進行登入資訊驗證
def backstage_interface(self):
account = self.input_account.get()#.ljust(10," ")
password = self.input_password.get()#.ljust(10," ")
#對賬戶資訊進行驗證,普通使用者返回user,管理員返回master,賬戶錯誤返回noAccount,密碼錯誤返回noPassword
verifyResult =self.log_verifyAccountData(account,password)
if verifyResult=='master':
self.root.destroy()
tkinter.messagebox.showinfo(title='miniWechat', message='進入管理介面')
elif verifyResult=='user':
t.name = account
self.start()
elif verifyResult=='noAccount':
tkinter.messagebox.showinfo(title='miniWechat', message='該賬號不存在請重新輸入!')
elif verifyResult=='noPassword':
tkinter.messagebox.showinfo(title='miniWechat', message='賬號/密碼錯誤請重新輸入!')
def run(self):
self.root.run()
def start(self):
self.root.destroy()
t.run()
main_user()
def log_verifyAccountData(self,account,password):
#向伺服器傳送資訊
t.connecntsocket.send(('root/'+'login'+'/'+account+'/'+password).encode())
sentense = t.connecntsocket.recv(2048).decode()
print(sentense)
return sentense
def reg_verifyAccountData(self,account,password):
t.connecntsocket.send(('root/'+'register'+'/'+account+'/'+password).encode())
sentense = t.connecntsocket.recv(2048).decode()
print(sentense)
return sentense
def my_close(self):
t.connecntsocket.send(('un_root').encode())
self.root.destroy()
sleep(1)
t.connecntsocket.close()
使用者介面
class User(object):
def __init__(self):
self.tk = Tk()
self.tk.title('使用者介面')
self.tk.protocol('WM_DELETE_WINDOW', self.my_close)
self.button_pos = 280
self.friend_list = [None]*80
self.friend_list_len = 0
self.to_be_friend_list = [None] * 80
self.to_be_friend_list_len = 0
#好友列表
self.friend_area = Canvas(self.tk, bg='pink')
self.friend_area.place(x=5, y=260, heigh=340, width=340)
self.friend_text = scrolledtext.ScrolledText(self.friend_area)
self.friend_text.place(x=5, y=5, heigh=340, width=330)
#待新增好友列表
self.to_be_friend_area = Canvas(self.tk,bg='pink')
self.to_be_friend_area.place(x=5, y=650, heigh=340, width=340)
self.to_be_friend_text = scrolledtext.ScrolledText(self.to_be_friend_area)
self.to_be_friend_text.place(x=5, y=5, heigh=340, width=340)
self.tk.geometry('350x1000')
# 執行程式碼時記得新增一個gif圖片檔案,不然是會出錯的
self.canvas = tkinter.Canvas(self.tk, height=200, width=350) # 建立畫布
self.image_file = tkinter.PhotoImage(file='1572079024477.gif')
self.image = self.canvas.create_image(0, 0, anchor='nw', image=self.image_file) # 將圖片置於畫布上
self.canvas.place(x=0,y=0)#pack(side='top') # 放置畫布(為上端)
# self.friend_list = tkinter.Button(self.tk, text='新增好友', bg='skyblue', command=self.to_chat, font=('Arial', 16))
# self.friend_list.place(x=20, y=280)
#新增TEXT文字
self.add_friend_label = tkinter.Label(self.tk, text='名字 ')
self.friend_list_label = tkinter.Label(self.tk, text='好友列表 ',bg='blue',fg='black',font=("華文行楷", 16),width=32,height=2)
self.to_be_friend_list_label = tkinter.Label(self.tk, text='待通過的好友請求 ',bg='blue',fg='black',font=("華文行楷", 16),width=32,height=2)
#新增輸入框
self.input_friend_name = tkinter.Entry(self.tk, width=20)
#新增按鈕
self.add_friend_button = tkinter.Button(self.tk, command=self.add_friend, text="確認新增", width=6)
self.delete_friend_button = tkinter.Button(self.tk, command=self.delete_friend, text="確認刪除", width=6)
self.refresh_all_button = tkinter.Button(self.tk, command=self.refresh_all, text="重新整理列表", width=10)
#放到指定位置
self.add_friend_label.place(x=0,y=181)
self.input_friend_name.place(x=35,y=182)
self.add_friend_button.place(x=180,y=180)
self.delete_friend_button.place(x=230, y=180)
self.refresh_all_button.place(x=280,y=180)
self.friend_list_label.place(x=10,y=210)
self.to_be_friend_list_label.place(x=10,y=600)
self.refresh_friend_list()
self.refresh_to_be_friend_list()
def refresh_to_be_friend_list(self):
self.to_be_friend_text.delete(0.0,END)
t.connecntsocket.send(('root/friend_op/print_to_be_friend_list/' + t.name).encode())
time.sleep(0.1)
self.to_be_deal_message = t.to_be_friend_list # deal_message中存放所有名字
print(self.to_be_deal_message)
self.to_be_friend_list_len = len(self.to_be_deal_message)
for i in range(0, self.to_be_friend_list_len):
self.create_to_be_friend_bottun(i, self.to_be_deal_message[i])
def refresh_friend_list(self):#重新整理好友列表
self.friend_text.delete(0.0,END)
t.connecntsocket.send(('root/friend_op/print_friend_list/'+t.name).encode())
time.sleep(0.1)
self.deal_message = t.friend_list#deal_message中存放所有名字
self.friend_list_len = len(self.deal_message)
for i in range(0, self.friend_list_len):
self.create_friend_bottun(i, self.deal_message[i])
def create_to_be_friend_bottun(self, i, name):
self.to_be_friend_list[i] = tkinter.Button(self.to_be_friend_text, text=name, bg='skyblue', command=lambda:self.whether_accpet(name), font=('Arial', 16), width=33, height=1)
self.to_be_friend_text.window_create(END, window=self.to_be_friend_list[i])
def create_friend_bottun(self,i,name):
self.friend_list[i] = tkinter.Button(self.friend_text, text=name, bg='skyblue', command=lambda:self.to_chat(name), font=('Arial', 16), width=23, height=1)
self.friend_text.window_create(END, window=self.friend_list[i])
def whether_accpet(self,name):
flag = messagebox.askokcancel(title='miniWechat', message=('是否接受' + name + '的好友請求?'))
if (flag == True):
t.connecntsocket.send(('root/friend_op/accept/'+t.name+'/'+name).encode())
else:
t.connecntsocket.send(('root/friend_op/reject/'+t.name+'/'+name).encode())
def to_chat(self,name):
print(name)
main_chat(name)
def refresh_all(self):
self.refresh_to_be_friend_list()
self.refresh_friend_list()
def delete_friend(self):
name = self.input_friend_name.get()
t.connecntsocket.send(('root/friend_op/delete/' + t.name + '/' + name).encode())
def add_friend(self):
name = self.input_friend_name.get()
print(type(name))
t.connecntsocket.send(('root/friend_op/add/'+t.name+'/'+name).encode())
print(name)
def handler(self,event, top, lb):
"""事件處理函式"""
content = lb.get(lb.curselection())
return messagebox.showinfo(title="Hey, you got me!", message="I am {0}".format(content), parent=top)
def handler_adaptor(self,fun, **kwds):
"""事件處理函式的介面卡,相當於中介"""
return lambda event, fun=fun, kwds=kwds: fun(event, **kwds)
def run(self):
self.tk.mainloop()
def my_close(self):
t.connecntsocket.send(('un_root').encode())
self.tk.destroy()
sleep(1)
t.connecntsocket.close()
聊天介面
class Chat(object):
def __init__(self,name):
self.root = Toplevel()
self.name = name
self.root.title(name)
self.root.protocol('WM_DELETE_WINDOW', self.my_close)
'''建立分割槽'''
self.f_msglist = Frame(self.root,height=300, width=300) # 建立<訊息列表分割槽 >
self.f_msgsend = Frame(self.root,height=300, width=300) # 建立<傳送訊息分割槽 >
self.f_floor = Frame(self.root,height=100, width=300) # 建立<按鈕分割槽>
self.f_right = Frame(self.root,height=700, width=100) # 建立<圖片分割槽>
'''建立控制元件'''
self.txt_msglist = Text(self.f_msglist) # 訊息列表分割槽中建立文字控制元件
self.txt_msglist.tag_config('green', foreground='blue') # 訊息列表分割槽中建立標籤
self.txt_msgsend = Text(self.f_msgsend) # 傳送訊息分割槽中建立文字控制元件
self.txt_msgsend.bind('<KeyPress-Up>', self.msgsendEvent) # 傳送訊息分割槽中,繫結‘UP’鍵與訊息傳送。
'''txt_right = Text(f_right) #圖片顯示分割槽建立文字控制元件'''
self.button_send = Button(self.f_floor, text='傳送', command=self.msgsend) # 按鈕分割槽中建立按鈕並繫結傳送訊息函式
self.button_cancel = Button(self.f_floor, text='取消', command=self.cancel) # 分割槽中建立取消按鈕並繫結取消函式
self.button_send_file = Button(self.f_floor, text='上傳', command=self.filesend)
self.button_resent_message = Button(self.f_floor, text='最近訊息', command=self.get_resent_message)
# self.photo = PhotoImage(file='1572079024477.gif')
# self.label = Label(self.f_right, image=self.photo) # 右側分割槽中新增標籤(繫結圖片)
self.label = Label(self.f_right)
# self.label.image = self.photo
self.canvas = Canvas(self.root, height=300, width=500) # 建立畫布
self.image_file = PhotoImage(file='15720790244771.gif')
self.image = self.canvas.create_image(0, 0, anchor='nw', image=self.image_file) # 將圖片置於畫布上
self.canvas.grid(row=1, column=1) # 放置畫布(為上端)
'''分割槽佈局'''
self.f_msglist.grid(row=0, column=0) # 訊息列表分割槽
self.f_msgsend.grid(row=1, column=0) # 傳送訊息分割槽
self.f_floor.grid(row=2, column=0) # 按鈕分割槽
self.f_right.grid(row=0, column=1, rowspan=3) # 圖片顯示分割槽
self.txt_msglist.grid() # 訊息列表文字控制元件載入
self.txt_msgsend.grid() # 訊息傳送文字控制元件載入
self.button_send.grid(row=0, column=0, sticky=W) # 傳送按鈕控制元件載入
self.button_cancel.grid(row=0, column=1, sticky=W) # 取消按鈕控制元件載入
self.button_send_file.grid(row=0, column=2, sticky=W)
self.button_resent_message.grid(row=0, column=3, sticky=W)
self.label.grid() # 右側分割槽載入標籤控制元件
def insert_message(self,massage_title,massage_content):
self.txt_msglist.insert(END, massage_title+'\n', 'green')
self.txt_msglist.insert(END, massage_content)
def insert_info(self,system_info):
self.txt_msglist.insert(END, system_info + '\n', 'red')
def get_resent_message(self):
resent_message = read_csv('resent_message.csv')
k = resent_message[resent_message.name == self.name].shape[0]
if (k == 0):
return
title1 = '/'.join(resent_message[resent_message.name == self.name].title.tolist())
message1 = '/'.join(resent_message[resent_message.name == self.name].message.tolist())
title = title1.split('/')
message = message1.split('/')
self.txt_msgsend.delete(0.0,END)
lenth = len(title)
for i in range(0,lenth):
self.txt_msglist.insert(END, title[i] + '\n', 'green')
self.txt_msglist.insert(END, message[i])
def msgsend(self):
self.msg = t.name + time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
self.txt_msglist.insert(END, self.msg + '\n', 'green') # 新增時間
self.txt_msglist.insert(END, self.txt_msgsend.get('0.0', END)) # 獲取傳送訊息,新增文字到訊息列表
message =self.msg+'/'+self.txt_msgsend.get('0.0', END)
mm=('root/chat/'+t.name+'/'+self.name+'/'+message)
print(mm)
t.connecntsocket.send(('root/chat/message/'+t.name+'/'+self.name+'/'+message).encode())
resent_message = read_csv('resent_message.csv')
new = DataFrame({'name': self.name, 'title': self.msg + '\n', 'message': self.txt_msgsend.get('0.0', END)}, index=[0])
resent_message = resent_message.append(new, ignore_index=True)
resent_message.to_csv('resent_message.csv', index=0)
self.txt_msgsend.delete('0.0', END) # 清空傳送訊息
'''定義取消傳送 訊息 函式'''
def filesend(self):
filepath = self.txt_msgsend.get('0.0', END)
self.txt_msgsend.delete('0.0', END) # 清空傳送訊息
t.connecntsocket.send(('root/chat/file/'+t.name+'/'+self.name+'/begin').encode())
filepath = filepath.strip('\n')
if os.path.isfile(filepath):
# 定義定義檔案資訊。128s表示檔名為128bytes長,l表示一個int或log檔案型別,在此為檔案大小
fileinfo_size = struct.calcsize('128sl')
# 定義檔案頭資訊,包含檔名和檔案大小
fhead = struct.pack('128sl', os.path.basename(filepath).encode('utf-8'), os.stat(filepath).st_size)
# 傳送檔名稱與檔案大小
t.connecntsocket.send(fhead)
# 將傳輸檔案以二進位制的形式分多次上傳至伺服器
fp = open(filepath, 'rb')
while 1:
data = fp.read(1024)
if not data:
print ('{0} file send over...'.format(os.path.basename(filepath)))
break
t.connecntsocket.send(data)
def cancel(self):
self.txt_msgsend.delete('0.0', END) # 取消傳送訊息,即清空傳送訊息
'''繫結up鍵'''
def msgsendEvent(self,event):
if event.keysym == 'Up':
self.msgsend()
def run(self):
self.root.mainloop()
def my_close(self):
self.root.destroy()
my_removw(self.name)
def my_removw(name):
for c in Chat_list:
if c.name == name:
Chat_list.remove(c)
return
執行效果圖
登入介面
使用者介面
聊天介面
相關文章
- Python + Tkinter簡單實現註冊登入(連線本地MySQL資料庫)PythonMySql資料庫
- 10.註冊和登入功能實現(3)—— 註冊資料寫入資料庫資料庫
- 如何實現檔案傳輸系統的多儲存
- 微信儲存的檔案在哪個資料夾
- javaweb專案(1)連線資料庫,登入註冊JavaWeb資料庫
- Springboot+Vue實現線上聊天室專案-登入、註冊介面的實現Spring BootVue
- swing 實現使用者登入註冊介面(不使用資料庫)資料庫
- 簡單實現登陸註冊gui介面以及打包成exe檔案GUI
- node+express+mongDB實現簡單登入註冊Express
- 微信授權註冊或微信登陸 微信授權登陸 基於若依vue 實現Vue
- 資料儲存--檔案儲存
- Laravel 自定義登入註冊頁面並使用 Ajax 進行資料傳輸Laravel
- 【node】檔案上傳功能簡易實現
- golang實現檔案上傳並轉存資料庫功能詳解Golang資料庫
- java實現微信登入Java
- Spring Boot+微信小程式_儲存微信登入者的個人資訊Spring Boot微信小程式
- 簡單登入註冊實現(Java物件導向複習)Java物件
- 傳統資料庫也能實現區塊鏈儲存資料庫區塊鏈
- iTerm2 實現 ssh 自動登入,並使用 Zmodem 實現快速傳輸檔案
- 【Python3網路爬蟲開發實戰】5-資料儲存-1 檔案儲存-2 JSON檔案儲存Python爬蟲JSON
- node+ajax+mysql實現登入註冊MySql
- HTML基礎實現簡單的註冊和登入頁面HTML
- 微信小程式入門從這裡出發(登入註冊、開發工具、檔案及結構介紹)微信小程式
- 簡單的登入註冊(前端+後端+MySQL資料庫 DRuid連線池 DBUtils)前端後端MySql資料庫UI
- 實現報表資料分庫儲存
- express+vue+mongodb+session 實現註冊登入ExpressVueMongoDBSession
- Laravel 實現 passport 使用者註冊登入LaravelPassport
- [資料庫系統]儲存和檔案結構資料庫
- CentOS修改Mariadb資料庫檔案儲存路徑CentOS資料庫
- 2、JSP實現資料傳遞和儲存JS
- 微信開發系列之七 - 使用Redis儲存微信聊天記錄Redis
- 資料庫檔案儲存(DBFS),是一款針對資料庫場景的雲原生共享檔案儲存服務資料庫
- SpringBoot整合阿里雲OSS物件儲存實現檔案上傳Spring Boot阿里物件
- Android中的資料儲存之檔案儲存Android
- 跨國大檔案傳輸需要哪些方面?怎麼實現資料快速傳輸?
- 使用JavaScript和Python實現Oracle資料庫的儲存過程?JavaScriptPythonOracle資料庫儲存過程
- python 儲存檔案jsonPythonJSON
- Python基於Socket實現簡易多人聊天室Python