主頁 > 後端開發 > Python聊天室(帶界面)主要實作技術:tkinter,Mysql,Treading,socket。功能:可私聊群聊,查看聊天記錄

Python聊天室(帶界面)主要實作技術:tkinter,Mysql,Treading,socket。功能:可私聊群聊,查看聊天記錄

2021-04-24 13:11:30 後端開發

一、前言

我用的是面向物件寫的,把界面功能模塊封裝成類,然后在客戶端創建物件然后進行呼叫,好處就是方便我們維護代碼以及把相應的資訊封裝起來,每一個實體都是各不相同的,

所有的界面按鈕處理事件都在客戶端,在創建界面物件是會把客戶端的處理事件函式作為創建物件的引數,之后再按鈕上系結這個函式,當點擊按鈕時便會回呼函式

二、登錄界面實作

登錄界面模塊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

上一篇:諾,你們要的Python進階來咯!【進階必備】

下一篇:Python爬取某趣閣小說,有趣又實用

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more