一、前言
我用的是面向物件寫的,把界面功能模塊封裝成類,然后在客戶端創建物件然后進行呼叫,好處就是方便我們維護代碼以及把相應的資訊封裝起來,每一個實體都是各不相同的,
所有的界面按鈕處理事件都在客戶端,在創建界面物件是會把客戶端的處理事件函式作為創建物件的引數,之后再按鈕上系結這個函式,當點擊按鈕時便會回呼函式
二、登錄界面實作
登錄界面模塊chat_login_panel.py
from tkinter import * # 匯入模塊,用戶創建GUI界面
# 登陸界面類
class LoginPanel:
# 構造方法,引數為按鈕事件處理函式,從客戶端main傳進來,可以實作按鈕回呼
def __init__(self, handle_login, handle_register, close_login_window):
# 初始化引數實體變數
self.handle_login = handle_login
self.handle_register = handle_register
self.close_login_window = close_login_window
# 顯示登錄界面的實體方法
def show_login_panel(self):
# 宣告全域變數方便,在靜態函式重呼叫
global login_frame
global frames
global imgLabel
global numIdx
self.login_frame = Tk() # 創建主視窗
# 設定背景顏色
self.login_frame.configure(background="white")
login_frame = self.login_frame # 系結全域變數
# 設定視窗關閉按鈕回呼,用于退出時關閉socket連接
self.login_frame.protocol("WM_DELETE_WINDOW", self.close_login_window)
# 得到螢屏寬度,高度
screen_width = self.login_frame.winfo_screenwidth()
screen_height = self.login_frame.winfo_screenheight()
# 宣告寬度,高度變數
width = 503
height = 400
# 設定視窗在螢屏局中變數
gm_str = "%dx%d+%d+%d" % (width, height, (screen_width - width) / 2,
(screen_height - 1.2 * height) / 2)
self.login_frame.geometry(gm_str) # 設定視窗局中
self.login_frame.title("登錄") # 設定視窗標題
# 設定視窗不能改變大小
self.login_frame.resizable(width=False, height=False)
numIdx = 10 # gif的幀數
# 回圈遍歷動圖的幀
frames = [PhotoImage(file='login.gif', format='gif -index %i' % (i)) for i in range(numIdx)]
# 創建存放gif的標簽
imgLabel = Label(self.login_frame, height=400, width=500)
# 設定標簽的位置
imgLabel.place(x=-252, y=-200, relx=0.5, rely=0.5, relwidth=1, relheigh=0.5)
# 設定文本標簽和位置
Label(login_frame, text="昵稱:", font=("宋體", 12), bg="white", fg="grey") \
.place(x=110, y=230)
Label(login_frame, text="密碼:", font=("宋體", 12), bg="white", fg="grey") \
.place(x=110, y=260)
# 宣告用戶名密碼變數
self.user_name = StringVar()
self.password = StringVar()
# 設定輸入框及位置
self.entry1=Entry(login_frame, textvariable=self.user_name, fg="black", width=25)
self.entry1.place(x=180, y=230)
self.entry2=Entry(login_frame, textvariable=self.password, show='*', fg="black", width=25)
self.entry2.place(x=180, y=260)
# 設定注冊按鈕及位置,按鈕事件為handle_register函式
self.button_register = Button(login_frame, text="注冊賬號", relief=FLAT, bg='white', fg='grey',
font=('黑體', 15), command=self.handle_register).place(x=0, y=370)
self.login_frame.bind('<Return>', self.handle_login) # 系結回車鍵
# 設定登錄按鈕及位置,按鈕事件為handle_login函式
self.button_login = Button(login_frame, text="登錄", bg="#00BFFF", fg="white", width=21, height=2,
font=('黑體', 15), command=lambda: self.handle_login(self))
self.button_login.place(x=160, y=300)
# 定時器函式,用于重繪gif的幀
@staticmethod
def update(idx):
frame = frames[idx]
idx += 1 # 下一張的序號
imgLabel.configure(image=frame)
login_frame.after(200, LoginPanel.update, idx % numIdx) # 200毫秒之后繼續執行定時器函式
# 呼叫定時器函式,執行回圈mainloop顯示界面實體方法
def load(self):
LoginPanel.update(0)
self.login_frame.mainloop()
# 關閉登錄界面實體方法
def close_login_panel(self):
if self.login_frame == None:
print("未顯示界面")
else:
# 關閉登錄界面
self.login_frame.destroy()
# 獲取輸入的用戶名密碼實體方法
def get_input(self):
return self.user_name.get(), self.password.get()
上面模塊把登錄界面封裝成類,這樣在客戶端就可以創建很多實體,每一個實體對應一個登錄界面
注意:上面模塊是給客戶端呼叫的,直接運行沒效果,下面給出客戶端呼叫登錄模塊顯示的效果

三、注冊界面實作
注冊界面模塊chat_login_panel.py
from tkinter import * # 匯入模塊,用戶創建GUI界面
from PIL import Image # 匯入處理影像模塊
# 注冊界面類
class RegisterPanel(object):
# 構造方法,引數為按鈕事件處理函式,從客戶端main傳進來,可以實作按鈕回呼
def __init__(self, file_open_face, close_register_window, register_submit):
# 初始化引數實體變數
self.file_open_face = file_open_face
self.close_register_window = close_register_window
self.register_submit = register_submit
self.file_name = "" # 檔案路徑
# 顯示注冊界面的實體方法
def show_register_panel(self):
# 宣告全域變數方便,在靜態函式重呼叫
global register_frame
global frames
global imgLabel
global numIdx
# 創建主視窗
self.register_frame = Tk()
register_frame = self.register_frame # 系結全域變數
# 設定背景顏色
self.register_frame.configure(background="white")
# 得到螢屏寬度,高度
screen_width = self.register_frame.winfo_screenwidth()
screen_height = self.register_frame.winfo_screenheight()
# 宣告寬度,高度變數
width = 503
height = 400
# 設定視窗在螢屏局中變數
gm_str = "%dx%d+%d+%d" % (width, height, (screen_width - width) / 2,
(screen_height - 1.2 * height) / 2)
# 設定視窗局中
self.register_frame.geometry(gm_str)
# 設定視窗標題
self.register_frame.title("注冊")
# 設定視窗不能改變大小
self.register_frame.resizable(width=False, height=False)
self.p1 = PhotoImage(file='添加頭像按鈕.png') # 把圖片轉化為PhotoImage型別
numIdx = 9 # gif的幀數
# 回圈遍歷動圖的幀
frames = [PhotoImage(file='register.gif', format='gif -index %i' % (i)) for i in range(numIdx)]
# 創建存放gif的標簽
imgLabel = Label(self.register_frame, height=400, width=500)
# 設定標簽的位置
imgLabel.place(x=-252, y=-200, relx=0.5, rely=0.5, relwidth=1, relheigh=0.5)
# 設定文本框,用戶存放頭像
self.face_show = Text(self.register_frame, bg="white", height=3.5, width=7,
highlightcolor="white")
# 設定文本框不可編輯
self.face_show.config(state=DISABLED)
# 設定文本框的位置
self.face_show.place(x=370, y=230)
# 宣告寬度高度,用來設定圖片大小
self.width = 50
self.height = 50
# 打開圖片,用在注冊頁面文本框中顯示默認頭像
img = Image.open("默認頭像.png")
# 設定圖片的大小
out = img.resize((self.width, self.height), Image.ANTIALIAS)
# 保存圖片,型別為png
out.save(r"頭像.png", 'png')
# 把頭像轉換為PhotoImage型別,用于在文本框顯示
self.p2 = PhotoImage(file='頭像.png')
# 設定文本框可編輯
self.face_show.config(state=NORMAL)
# 把頭像圖片插入文本框
self.face_show.image_create(END, image=self.p2)
# 設定文本框不可編輯
self.face_show.config(state=DISABLED)
# 設定文本框滑到最低
self.face_show.see(END)
# 設定文本標簽及位置
Label(self.register_frame, text="用戶名:", font=("宋體", 12), bg="white", fg="grey") \
.place(x=60, y=230)
Label(self.register_frame, text="密 碼:", font=("宋體", 12), bg="white", fg="grey") \
.place(x=60, y=260)
Label(self.register_frame, text="確認密碼:", font=("宋體", 12), bg="white", fg="grey") \
.place(x=60, y=290)
# 宣告用戶名,密碼,確認密碼變數
self.user_name = StringVar()
self.password = StringVar()
self.confirm_password = StringVar()
# 設定輸入文本框和位置,用于獲取用戶的輸入
Entry(self.register_frame, textvariable=self.user_name, fg="black", width=30) \
.place(x=140, y=230)
Entry(self.register_frame, textvariable=self.password, show="*", fg="black", width=30) \
.place(x=140, y=260)
Entry(self.register_frame, textvariable=self.confirm_password, show="*", fg="black", width=30) \
.place(x=140, y=290)
# 設定退出注冊頁面按鈕及位置,按鈕事件為close_register_window函式
self.botton_quit = Button(self.register_frame, text="回傳", relief=FLAT, bg='white', fg="grey",
font=('黑體', 15), command=self.close_register_window).place(x=0, y=370)
self.register_frame.bind('<Return>', self.register_submit) # 系結注冊按鈕回車事件
# 設定注冊按鈕及位置,按鈕事件為register.submit函式
self.botton_register = Button(self.register_frame, text="立即注冊", bg="#00BFFF", fg="white", width=27, height=2,
font=('黑體', 15), command=lambda: self.register_submit(self)).place(x=120, y=330)
# 設定添加頭像按鈕及位置,事件處理為為file_open_face函式
self.botton_file_open = Button(self.register_frame, image=self.p1, relief=FLAT, bd=0,
command=self.file_open_face).place(x=430, y=230)
# 定時器靜態函式,用于重繪gif的幀
@staticmethod
def update(idx):
frame = frames[idx]
idx += 1 # 下一張的序號
imgLabel.configure(image=frame)
register_frame.after(200, RegisterPanel.update, idx % numIdx) # 200毫秒之后繼續執行定時器函式
# 呼叫定時器函式,執行回圈mainloop顯示界面實體方法
def load(self):
RegisterPanel.update(0)
self.register_frame.mainloop()
# 添加頭像實體方法
def add_face(self, file_name):
self.file_name = file_name
# 打開圖片
img = Image.open(file_name)
# 設定圖片大小
out = img.resize((self.width, self.height), Image.ANTIALIAS)
# 保存圖片,型別為png
out.save(r"頭像.png", 'png')
# 把頭像轉化為PhotoImage
self.p = PhotoImage(file='頭像.png')
# 設定文本框可編輯
self.face_show.config(state=NORMAL)
self.face_show.delete('0.0', END)
# 把頭像插入文本框
self.face_show.image_create(END, image=self.p)
# 設定文本不可編輯
self.face_show.config(state=DISABLED)
# 設定文本框滑到最低
self.face_show.see(END)
# 關閉注冊界面實體方法
def close_register_panel(self):
if self.register_frame == None:
print("未顯示界面")
else:
# 關閉注冊界面
self.register_frame.destroy()
# 獲取輸入的用戶名、密碼、確認密碼實體方法
def get_input(self):
return self.user_name.get(), self.password.get(), self.confirm_password.get(), self.file_name
下面簡單介紹下客戶端如何呼叫注冊界面:
當運行main客戶端模塊時,首先會創建一個chat_logiin_panel的物件,然后呼叫物件的實體方法顯示登錄界面,如果用戶點擊了注冊按鈕,則會觸發事件handle_register函式,這個函式是從main客戶端創建物件時作為引數傳進來的,之后便會在客戶端中的handdle_register函式中創建chat_register_panel物件,再呼叫實體方法顯示注冊界面,其他的呼叫類似是,下面不再闡述
注意:上面模塊是給客戶端呼叫的,直接運行沒效果,下面給出客戶端呼叫注冊模塊顯示的效果

四、聊天界面實作
聊天界面模塊chat_main_panel.py
from tkinter import * # 匯入模塊,用戶創建GUI界面
import tkinter.font as tf
import time
import chat_mysql # 匯入處理mysql的模塊
from PIL import Image # 匯入處理影像模塊
# 主界面類
class MainPanel:
def __init__(self, user_name, send_message, send_mark, refurbish_user, private_talk, close_main_window):
print("初始化主界面")
self.user_name = user_name
self.send_message = send_message
self.private_talk = private_talk
self.close_main_window = close_main_window
# 用字典將標記與表情圖片一一對應, 用于后面接收標記判斷表情貼圖
self.dic = {}
self.ee = 0 # 判斷表情面板開關的標志
self.send_mark = send_mark
self.refurbish_user = refurbish_user
self.mark_flag = ""
self.face = []
def show_main_panel(self):
# 宣告全域變數,方便在靜態函式中呼叫用
global main_frame
global frames
global imgLabel
global numIdx
# 創建主視窗
main_frame = Tk()
# 把全域變數系結在實體變數上
self.main_frame = main_frame
# 設定主視窗標題
self.main_frame.title("python聊天室")
# 設定主視窗顏色
self.main_frame.configure(background="white")
# 設定關閉主視窗的回呼函式
self.main_frame.protocol("WM_DELETE_WINDOW", self.close_main_window)
# 宣告寬度,高度變數用于設定主視窗局中
width = 1300
height = 700
# 獲取螢屏的高度,寬度
screen_width = self.main_frame.winfo_screenwidth()
screen_height = self.main_frame.winfo_screenheight()
# 設定主視窗局中的變數
gm_str = "%dx%d+%d+%d" % (width, height, (screen_width - width) / 2,
(screen_height - 1.2 * height) / 2)
# 設定主視窗局中
self.main_frame.geometry(gm_str)
# 設定視窗不能改變大小
self.main_frame.resizable(width=False, height=False)
# 表情圖片,把圖片轉換為PhotoImage,
self.p1 = PhotoImage(file='微信表情1.png')
self.p2 = PhotoImage(file='微信表情2.png')
self.p3 = PhotoImage(file='微信表情3.png')
self.p4 = PhotoImage(file='微信表情4.png')
self.p5 = PhotoImage(file='微信表情5.png')
self.p6 = PhotoImage(file='微信表情6.png')
self.p7 = PhotoImage(file='微信表情7.png')
self.p8 = PhotoImage(file='微信表情8.png')
self.p9 = PhotoImage(file='微信表情9.png')
self.p10 = PhotoImage(file='微信表情10.png')
# 按鈕圖片,把圖片轉換為PhotoImage
self.p11 = PhotoImage(file='表情按鈕.png')
self.p12 = PhotoImage(file='聊天記錄按鈕.png')
# 表情包字典,每一個表情包對應一個標記
self.dic = {'aa**': self.p1, 'bb**': self.p2, 'cc**': self.p3, 'dd**': self.p4, 'ee**': self.p5,
'ff**': self.p6, 'gg**': self.p7, 'hh**': self.p8, 'jj**': self.p9, 'kk**': self.p10}
# 設定文本標簽和位置
self.label1 = Label(self.main_frame, text=" 在線用戶 python聊天室歡迎您:" + self.user_name + " "
" "
" " +
" ", font=("黑體", 20), bg="#00BFFF", fg="white")
self.label1.grid(row=0, column=0, ipady=0, padx=0, columnspan=3, sticky=E+W)
# 在線用戶串列框
friend_list_var = StringVar() # 宣告串列框變數
# 設定串列框及位置
self.friend_list = Listbox(self.main_frame, selectmode=NO, listvariable=friend_list_var,
bg="#F8F8FF", fg="#00BFFF", font=("宋體", 14),
highlightcolor="white", selectbackground="#00BFFF")
self.friend_list.grid(row=1, column=0, rowspan=3, sticky=N + S, padx=0, pady=(0, 0))
self.friend_list.bind('<ButtonRelease-1>', self.private_talk) # 系結串列框點擊事件
# 設定串列框的縮放比例
main_frame.rowconfigure(1, weight=1) # 設定主視窗第一行的縮放比例,也就是串列框
main_frame.columnconfigure(1, weight=1) # 設定列的縮放比例
sc_bar = Scrollbar(self.main_frame, activebackground='red') # 設定串列框滾動條
sc_bar.grid(row=1, column=0, sticky=N + S + E, rowspan=3, pady=(0, 3)) # 設定滾動條的位置
# 串列框和滾動條的系結
sc_bar['command'] = self.friend_list.yview
self.friend_list['yscrollcommand'] = sc_bar.set
# 設定訊息框的滾動條
msg_sc_bar = Scrollbar(self.main_frame) # 設定滾動條
msg_sc_bar.grid(row=1, column=1, sticky=E + N + S, padx=(0, 1), pady=1) # 設定滾動條的位置
# 顯示訊息的文本框
self.message_text = Text(self.main_frame, bg="white", height=1,
highlightcolor="white", highlightthickness=1)
# 顯示訊息的文本框不可編輯,當需要修改內容時再修改版為可以編輯模式 NORMAL
self.message_text.config(state=DISABLED)
# 設定訊息框的位置
self.message_text.grid(row=1, column=1, sticky=W + E + N + S, padx=(0, 15), pady=(0, 27))
numIdx = 6 # gif的幀數
# 回圈遍歷動圖的幀
frames = [PhotoImage(file='main.gif', format='gif -index %i' % (i)) for i in range(numIdx)]
# 創建存盤gif的標簽
imgLabel = Label(self.main_frame, height=400, width=490)
# 設定標簽的位置
imgLabel.grid(row=1, column=2, sticky=W + E + N + S, rowspan=100, padx=(0, 0), pady=(160, 175))
# 系結訊息框和訊息框滾動條
msg_sc_bar["command"] = self.message_text.yview
self.message_text["yscrollcommand"] = msg_sc_bar.set
# 設定發送訊息框滾動條
send_sc_bar = Scrollbar(self.main_frame) # 創建滾動條
# 設定滾動條的位置
send_sc_bar.grid(row=2, column=1, sticky=E + N + S, padx=(0, 1), pady=1)
# 發送訊息框
self.send_text = Text(self.main_frame, bg="white", height=11, highlightcolor="white",
highlightbackground="#444444", highlightthickness=0)
# 滾動到底部
self.send_text.see(END)
# 設定訊息框的位置
self.send_text.grid(row=2, column=1, sticky=W + E + N + S, padx=(0, 15), pady=0)
# 系結發送訊息框和發送訊息框滾動條
send_sc_bar["command"] = self.send_text.yview
self.send_text["yscrollcommand"] = send_sc_bar.set
self.main_frame.bind('<Return>', self.send_message) # 系結發送按鈕回車事件
# 設定發送訊息按鈕及位置,事件處理函式為send_message
button1 = Button(self.main_frame, command=lambda: self.send_message(self), text="發送", bg="#00BFFF",
fg="white", width=13, height=2, font=('黑體', 12),)
button1.place(x=650, y=640)
# 設定關閉視窗按鈕及位置,事件處理函式為close_main_window
button2 = Button(self.main_frame, text="關閉", bg="white", fg="black", width=13, height=2,
font=('黑體', 12), command=self.close_main_window)
button2.place(x=530, y=640)
# 設定表情包按鈕及位置,事件處理為實體方法express
botton4 = Button(self.main_frame, command=self.express, image=self.p11, relief=FLAT, bd=0)
botton4.place(x=214, y=525)
# 設定聊天記錄按鈕及位置,事件處理為create_window實體方法
botton5 = Button(self.main_frame, command=self.create_window, image=self.p12, relief=FLAT, bd=0)
botton5.place(x=250, y=525)
# 設定重繪用戶串列按鈕及位置,事件處理為refurbish_user函式
botton5 = Button(self.main_frame, command=self.refurbish_user, text="重繪在線用戶", bg="#00BFFF", fg="white",
width=13, height=2, font=('黑體', 12),)
botton5.place(x=40, y=650)
# 定義器靜態函式,用于重繪gif的幀
@staticmethod
def update(idx):
frame = frames[idx]
idx += 1 # 下一張的序號
imgLabel.configure(image=frame)
main_frame.after(100, MainPanel.update, idx % numIdx) # 100毫秒之后繼續執行定時器函式
# 呼叫定時器函式,執行回圈mainloop顯示界面實體方法
def load(self):
MainPanel.update(0)
self.main_frame.mainloop()
# 聊天記錄按鈕處理事件實體方法
def create_window(self):
top1 = Toplevel() # 創建子視窗
top1.configure(background="#FFFAFA") # 設定子視窗顏色
# 得到螢屏寬度,高度
screen_width = top1.winfo_screenwidth()
screen_height = top1.winfo_screenheight()
# 宣告寬度,高度變數
width = 600
height = 650
# 設定視窗在螢屏局中變數
gm_str = "%dx%d+%d+%d" % (width, height, (screen_width - width) / 2,
(screen_height - 1.2 * height) / 2)
top1.geometry(gm_str) # 設定視窗局中
top1.title("聊天記錄") # 設定視窗標題
# 設定視窗不能改變大小
top1.resizable(width=False, height=False)
# 設定文本標簽
title_lable = Label(top1, text="聊天記錄", font=('粗斜體', 20, 'bold italic'),
fg="white", bg="#00BFFF")
# 設定文本在視窗的位置
title_lable.pack(ipady=10, fill=X)
# 設定文本框,用戶存放聊天記錄資訊
self.chatting_records = Text(top1, bg="white", height=50, highlightcolor="white", highlightthickness=1)
# 設定位置
self.chatting_records.pack(ipady=10, fill=X)
# 顯示訊息的文本框不可編輯,當需要修改內容時再修改版為可以編輯模式 NORMAL
self.chatting_records.config(state=DISABLED)
# 設定清除聊天記錄按鈕及位置
botton = Button(top1, text="清空聊天記錄", command=self.clear_chatting_records, bg="#00BFFF",
fg="white", width=12, height=2, font=('黑體', 11))
botton.place(x=490, y=600)
# 呼叫實體方法顯示聊天記錄
self.show_chatting_records()
# 顯示聊天記錄的實體方法
def show_chatting_records(self):
# 設定文本框可編輯
self.chatting_records.config(state=NORMAL)
# 打開用戶的存放聊天記錄的本地檔案
f = open("C:/Users/Administrator/PycharmProjects/pythonProject/chatting_records/" + self.user_name + ".txt", 'r')
while True:
content = f.readline() # 每次讀取一行
ft = tf.Font(family='微軟雅黑', size=13) # 設定字體樣式和大小變數
# 設定顏色和字體樣式及大小
self.chatting_records.tag_config("tag_9", foreground="#00BFFF", font=ft)
if content != "": # 如果不為空則在文本框最后一行插入文本
self.chatting_records.insert(END, content, 'tag_9')
else:
self.chatting_records.config(state=DISABLED) #否則則設定文本框不可編輯
return
# 清除聊天記錄按鈕處理實體方法
def clear_chatting_records(self):
# 設定文本框可編輯
self.chatting_records.config(state=NORMAL)
self.chatting_records.delete('1.0', END) # 洗掉文本框內容
# 打開聊天記錄檔案,以覆寫的形式寫入內容
a = open("C:/Users/Administrator/PycharmProjects/pythonProject/chatting_records/" + self.user_name + ".txt",
'w')
a.write("") # 插入空字串,則聊天記錄會被覆寫
a.close() # 關閉
self.chatting_records.config(state=DISABLED) # 設定文本不可編輯
# 保存聊天記錄實體方法
def sava_chatting_records(self, content):
# 打開聊天記錄檔案
a = open("C:/Users/Administrator/PycharmProjects/pythonProject/chatting_records/" + self.user_name + ".txt", 'a')
a.write(content) # 寫入資訊
a.close() # 關閉
# 定義表情包按鈕處理事件實體方法
def express(self):
# 如果ee標記為0,則彈出表情包,否則銷毀表情包
if self.ee == 0:
self.ee = 1 # 把標記置為1,用于下次點擊按鈕時銷毀表情
# 設定表情圖按鈕及相應的事件處理實體方法
self.b1 = Button(self.main_frame, command=self.bb1, image=self.p1, relief=FLAT, bd=0)
self.b2 = Button(self.main_frame, command=self.bb2, image=self.p2, relief=FLAT, bd=0)
self.b3 = Button(self.main_frame, command=self.bb3, image=self.p3, relief=FLAT, bd=0)
self.b4 = Button(self.main_frame, command=self.bb4, image=self.p4, relief=FLAT, bd=0)
self.b5 = Button(self.main_frame, command=self.bb5, image=self.p5, relief=FLAT, bd=0)
self.b6 = Button(self.main_frame, command=self.bb6, image=self.p6, relief=FLAT, bd=0)
self.b7 = Button(self.main_frame, command=self.bb7, image=self.p7, relief=FLAT, bd=0)
self.b8 = Button(self.main_frame, command=self.bb8, image=self.p8, relief=FLAT, bd=0)
self.b9 = Button(self.main_frame, command=self.bb9, image=self.p9, relief=FLAT, bd=0)
self.b10 = Button(self.main_frame, command=self.bb10, image=self.p10, relief=FLAT, bd=0)
# 設定表情包的位置
self.b1.place(x=207, y=480)
self.b2.place(x=255, y=480)
self.b3.place(x=303, y=480)
self.b4.place(x=351, y=480)
self.b5.place(x=399, y=480)
self.b6.place(x=207, y=430)
self.b7.place(x=255, y=430)
self.b8.place(x=303, y=430)
self.b9.place(x=351, y=430)
self.b10.place(x=399, y=430)
else:
# 標記ee為0則銷毀所有表情按鈕
self.ee = 0
self.b1.destroy()
self.b2.destroy()
self.b3.destroy()
self.b4.destroy()
self.b5.destroy()
self.b6.destroy()
self.b7.destroy()
self.b8.destroy()
self.b9.destroy()
self.b10.destroy()
# 所有表情按鈕處理實體方法
def bb1(self):
self.mark('aa**') # 呼叫實體方法,把引數傳過去
def bb2(self):
self.mark('bb**')
def bb3(self):
self.mark('cc**')
def bb4(self):
self.mark('dd**')
def bb5(self):
self.mark('ee**')
def bb6(self):
self.mark('ff**')
def bb7(self):
self.mark('gg**')
def bb8(self):
self.mark('hh**')
def bb9(self):
self.mark('jj**')
def bb10(self):
self.mark('kk**')
# 處理發送表情的實體方法
def mark(self, exp): # 引數是發的表情圖示記, 發送后將按鈕銷毀
self.send_mark(exp) # 函式回呼把標記作為引數
# 發送完摧毀所有表情包
self.b1.destroy()
self.b2.destroy()
self.b3.destroy()
self.b4.destroy()
self.b5.destroy()
self.b6.destroy()
self.b7.destroy()
self.b8.destroy()
self.b9.destroy()
self.b10.destroy()
self.ee = 0 # 把標記置為0
# 重繪在線串列實體方法
def refresh_friends(self, online_number, names):
self.friend_list.delete(0, END) # 先洗掉在線串列
for name in names: # 回圈插入在線用戶
self.friend_list.insert(0, name)
self.friend_list.insert(0, "【群聊】") # 在第二行插入群聊
self.friend_list.itemconfig(0, fg="#00BFFF") # 設定群聊字體顏色
self.friend_list.insert(0, '在線用戶數: ' + str(online_number)) # 在第一行插入在線用戶數
self.friend_list.itemconfig(0, fg="#FF00FF") # 設定在線用戶數顏色
# 接受到訊息,在文本框中顯示,自己的訊息用藍色,別人的訊息用綠色
def show_send_message(self, user_name, content, chat_flag):
self.message_text.config(state=NORMAL) # 設定訊息框可編輯
# 設定發送的訊息的用戶名和時間變數
title = user_name + " " + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + "\n"
if content == '* 系統提示: ' + user_name + ' 加入聊天室': # 加入聊天室標記處理
ft = tf.Font(family='微軟雅黑', size=13) # 設定字體樣式和大小變數
# 設定字體顏色樣式及大小
self.message_text.tag_config("tag_1", foreground="#FF00FF", font=ft)
self.message_text.insert(END, content + "\n", 'tag_1') # 在最后一行插入訊息
self.message_text.config(state=DISABLED) # 設定不可編輯
elif content == '* 系統提示: ' + user_name + ' 已離開群聊': # 離開聊天室標記處理
ft = tf.Font(family='微軟雅黑', size=13)
self.message_text.tag_config("tag_2", foreground="#DC143C", font=ft)
self.message_text.insert(END, content + "\n", 'tag_2')
self.message_text.config(state=DISABLED)
elif user_name == self.user_name: # 如果發送訊息的用戶是自己
if chat_flag == "group_chat": # 如果標記是群聊標記,則自己的訊息用藍色
print("group_chat====" + chat_flag)
ft = tf.Font(family='微軟雅黑', size=13)
self.message_text.tag_config("tag_4", foreground="#00BFFF", font=ft)
self.message_text.insert(END, title, 'tag_4')
self.sava_chatting_records(title) # 呼叫實體方法保存聊天記錄
elif chat_flag == "private_chat": # 如果是標記是私聊,則訊息用紅色
print("chat_flag====" + chat_flag)
ft = tf.Font(family='微軟雅黑', size=13)
self.message_text.tag_config("tag_5", foreground="#DC143C", font=ft)
self.message_text.insert(END, title, 'tag_5')
self.sava_chatting_records(title)
else: # # 如果發送訊息的用戶不是自己
if chat_flag == "group_chat": # 如果標記是群聊,則訊息用綠色
print("group_chat====" + chat_flag)
ft = tf.Font(family='微軟雅黑', size=13)
self.message_text.tag_config("tag_6", foreground="#008000", font=ft)
self.message_text.insert(END, title, 'tag_6')
self.sava_chatting_records(title)
elif chat_flag == "private_chat": # 標記是私聊,則訊息用紅色
print("chat_flag====" + chat_flag)
ft = tf.Font(family='微軟雅黑', size=13)
self.message_text.tag_config("tag_7", foreground="#DC143C", font=ft)
self.message_text.insert(END, title, 'tag_7')
self.sava_chatting_records(title)
if content in self.dic: # 判斷訊息是否為表情標記
chat_mysql.LogInformation.fing_face(user_name) # 去資料庫中讀取用戶的頭像
time.sleep(0.3) # 設定時間緩沖,給資料庫讀取用戶頭像以及保存到本地檔案的時間緩沖
# 打開圖片
self.img1 = Image.open("用戶頭像.png") # 打開資料庫保存的本地檔案
# 設定圖片大小
self.out1 = self.img1.resize((50, 50), Image.ANTIALIAS)
# 保存圖片,型別為png
self.out1.save(r"用戶頭像1.png", 'png')
time.sleep(0.3) # 給修改圖片大小以及保存修改后的圖片留時間快取
# 把頭像轉化為PhotoImage
self.face.append(PhotoImage(file='用戶頭像1.png')) # 把頭像圖片加入到串列中
self.message_text.image_create(END, image=self.face[-1]) # 插入串列最后一個頭像
self.message_text.insert(END, " : ")
self.message_text.image_create(END, image=self.dic[content]) # 插入表情
self.message_text.insert(END, "\n")
self.message_text.config(state=DISABLED)
# 滾動到最底部
self.message_text.see(END)
# 內容是訊息的處理
elif content != '* 系統提示: ' + user_name + ' 加入聊天室' and content != '* 系統提示: ' + user_name + ' 已離開群聊':
chat_mysql.LogInformation.fing_face(user_name)
time.sleep(0.3)
# 打開圖片
self.img2 = Image.open("用戶頭像.png")
# 設定圖片大小
self.out2 = self.img2.resize((50, 50), Image.ANTIALIAS)
# 保存圖片,型別為png
self.out2.save(r"用戶頭像2.png", 'png')
time.sleep(0.3)
self.face.append(PhotoImage(file='用戶頭像2.png'))
self.message_text.image_create(END, image=self.face[-1])
self.message_text.insert(END, " : ")
ft = tf.Font(family='微軟雅黑', size=15)
self.message_text.tag_config("tag_8", foreground="#000000", font=ft)
self.message_text.insert(END, content, 'tag_8') # 插入訊息
self.message_text.config(state=DISABLED)
# 滾動到最底部
self.message_text.see(END)
# 保存聊天記錄
self.sava_chatting_records(content)
self.sava_chatting_records("------------------------------------------------------------------------------\n")
# 群聊私聊改變標簽的實體方法
def change_title(self, title):
self.label1['text'] = title
# 清空發送訊息輸入框的實體方法
def clear_send_text(self):
self.send_text.delete('0.0', END)
# 獲取訊息輸入框內容的實體方法
def get_send_text(self):
return self.send_text.get('0.0', END)
注意:上面模塊是給客戶端呼叫的,運行沒效果,下面給出客戶端呼叫聊天界面模塊顯示的效果,下面效果演示了群聊私聊功能,以及加入聊天室和退出聊天室訊息

至此所有界面都實作了,這些界面被封裝成類,劃分成單獨的模塊,單獨運行是沒效果的,需要通過主函式也就是客戶端來呼叫,然后通過用戶的操作進行相應的呼叫
先告一段落,后面補上服務器和socket客戶端以及主程式,Mysql代碼模塊
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/279602.html
標籤:python
