PyQt简单示例聊天程序

PyQt简单示例聊天程序

效果展示:

https://s1.ax1x.com/2022/03/25/qYbMwQ.gif

代码:

from PyQt5.Qt import *
from talk import Ui_Form
import socket
import sys
import time

class Window(QWidget,Ui_Form):
    def __init__(self, parent=None, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)
        self.setupUi(self)
        ipaddress = Socket_Client.get_ip() #调用类方法进行获取ip
        self.lineEdit_3.setText(ipaddress)
        self.radioButton.setChecked(True)
        self.lineEdit_4.setText("8888")
        self.pushButton.clicked.connect(self.socket_connect)
        self.pushButton_2.clicked.connect(self.send_message)
        self.radioButton.toggled.connect(self.switch_client_server)

    def switch_client_server(self):
        print("switch")
        self.pushButton.clicked.connect(self.socket_server)
        self.pushButton_2.clicked.connect(self.server_send_data)

    def socket_connect(self): #连接按钮绑定函数,建立socket连接
        QCoreApplication.processEvents();
        try:
            self.socket_client = Socket_Client(self.lineEdit_3.text(),int(self.lineEdit_4.text()))
            self.socket_client.client_socket()
            self.setWindowTitle("聊天程序1.0 连接成功")
            self.thread_1 = Thread_recv(self.socket_client,self.textEdit_2)
            self.thread_1.start()
        except Exception as e:
            print(e)
            print("error")
            self.setWindowTitle("聊天程序1.0 连接失败")

    def socket_server(self):  #服务端函数
        QCoreApplication.processEvents();
        try:
            self.server_socket = Socket_Client(self.lineEdit_3.text(),int(self.lineEdit_4.text()))
            self.server_socket.server_socket()
            self.setWindowTitle("聊天程序1.0 服务开启成功")
            self.thread_2 = Thread_sev(self.server_socket,self.textEdit_2)
            self.thread_2.start()
        except Exception as e:
            print(e)
            self.setWindowTitle("聊天程序1.0 服务开启失败")

    def send_message(self):#发送消息

        try:
            self.socket_client.send_data(self.textEdit.toPlainText())
            localtime = time.strftime("%H:%M:%S")
            self.textEdit_2.append(f"[{localtime}]:"+"发送成功!")
            self.textEdit_2.append(f"[{localtime}]:" + "我说:" + self.textEdit.toPlainText() )
            self.textEdit.clear()
            self.textEdit.moveCursor(QTextCursor.End)
        except Exception as e:
            print(e)

    def server_send_data(self):
        try:
            self.server_socket.server_send_data(self.textEdit.toPlainText())
            localtime = time.strftime("%H:%M:%S")
            self.textEdit_2.append(f"[{localtime}]:" + "发送成功!")
            self.textEdit_2.append(f"[{localtime}]:" + "我说:" + self.textEdit.toPlainText())
            self.textEdit.clear()
            self.textEdit.moveCursor(QTextCursor.End)
        except Exception as e:
            print(e)

class Thread_recv(QThread):
    def __init__(self, recv,text_edit):
        super().__init__()
        self.recv = recv
        self.text_edit = text_edit

    def run(self):
        while True:
            self.recv_data = self.recv.recv_data()
            print(self.recv_data)
            localtime = time.strftime("%H:%M:%S")
            self.text_edit.append( f"[{localtime}]:" +"对方说:"+ self.recv_data)

class Thread_sev(QThread):
    def __init__(self,server_socket,text_edit):
        super().__init__()
        self.server = server_socket
        self.text = text_edit

    def run(self):
        self.server.server_accept()
        print(self.server.client_ip_port)
        localtime = time.strftime("%H:%M:%S")
        self.text.append(f"[{localtime}]:" + f"客户端连接成功:{self.server.client_ip_port[0]}")
        while True:
            self.data = str(self.server.client.recv(1024),"gbk")
            print(self.data)
            localtime = time.strftime("%H:%M:%S")
            self.text.append(f"[{localtime}]:" + "对方说:" + self.data)

class Socket_Client(object):
    def __init__(self,ipadress,port):
        self.ipaddress = ipadress
        self.port = port

    @classmethod
    def get_ip(cls):
        socket_ip = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        try:
            socket_ip.connect(('10.255.255.255', 1))
            return socket_ip.getsockname()[0]
        except Exception:
            return '127.0.0.1'
        finally:
            socket_ip.close()

    def client_socket(self):
        self.client_connect = socket.socket(family=-1,type=-1)
        self.client_connect.connect((self.ipaddress,self.port))

    def close_socket(self):
        self.client_connect.close()

    def server_socket(self):
        self.server_connect = socket.socket(family=-1,type=-1)
        self.server_connect.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
        self.server_connect.bind((self.ipaddress,self.port))
        self.server_connect.listen(128)

    def server_accept(self):
        self.client,self.client_ip_port = self.server_connect.accept()

    def server_send_data(self,data):
        data = data.encode('gbk')
        print(data)
        self.client.send(data)

    def send_data(self,data):
        data = data.encode('gbk')  #进行gbk编码
        print(data)
        self.client_connect.send(data)

    def recv_data(self):
        recv = str(self.client_connect.recv(1024),'gbk') #以gbk方式转码
        return recv

if __name__ == '__main__':

    app = QApplication(sys.argv)
    window =   Window()
    window.setWindowTitle("聊天程序1.0")
    window.show()
    sys.exit(app.exec())

界面示意图:

https://s1.ax1x.com/2022/03/25/qYOPwF.png

界面代码:

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'C:\Users\Administrator\Desktop\qt\talk\talk.ui'
#
# Created by: PyQt5 UI code generator 5.15.2
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(400, 300)
        self.pushButton = QtWidgets.QPushButton(Form)
        self.pushButton.setGeometry(QtCore.QRect(290, 40, 93, 28))
        self.pushButton.setObjectName("pushButton")
        self.pushButton_2 = QtWidgets.QPushButton(Form)
        self.pushButton_2.setGeometry(QtCore.QRect(290, 90, 93, 28))
        self.pushButton_2.setObjectName("pushButton_2")
        self.lineEdit = QtWidgets.QLineEdit(Form)
        self.lineEdit.setGeometry(QtCore.QRect(20, 10, 31, 20))
        self.lineEdit.setObjectName("lineEdit")
        self.lineEdit_2 = QtWidgets.QLineEdit(Form)
        self.lineEdit_2.setGeometry(QtCore.QRect(20, 150, 31, 20))
        self.lineEdit_2.setObjectName("lineEdit_2")
        self.radioButton = QtWidgets.QRadioButton(Form)
        self.radioButton.setGeometry(QtCore.QRect(300, 130, 93, 31))
        self.radioButton.setObjectName("radioButton")
        self.radioButton_2 = QtWidgets.QRadioButton(Form)
        self.radioButton_2.setGeometry(QtCore.QRect(300, 160, 93, 31))
        self.radioButton_2.setObjectName("radioButton_2")
        self.lineEdit_3 = QtWidgets.QLineEdit(Form)
        self.lineEdit_3.setGeometry(QtCore.QRect(280, 220, 111, 31))
        self.lineEdit_3.setText("")
        self.lineEdit_3.setObjectName("lineEdit_3")
        self.label = QtWidgets.QLabel(Form)
        self.label.setGeometry(QtCore.QRect(310, 200, 54, 12))
        self.label.setObjectName("label")
        self.label_2 = QtWidgets.QLabel(Form)
        self.label_2.setGeometry(QtCore.QRect(290, 260, 41, 21))
        font = QtGui.QFont()
        font.setFamily("Arial")
        self.label_2.setFont(font)
        self.label_2.setLayoutDirection(QtCore.Qt.RightToLeft)
        self.label_2.setAutoFillBackground(False)
        self.label_2.setObjectName("label_2")
        self.lineEdit_4 = QtWidgets.QLineEdit(Form)
        self.lineEdit_4.setGeometry(QtCore.QRect(320, 260, 61, 21))
        self.lineEdit_4.setObjectName("lineEdit_4")
        self.textEdit = QtWidgets.QTextEdit(Form)
        self.textEdit.setGeometry(QtCore.QRect(20, 40, 241, 101))
        self.textEdit.setObjectName("textEdit")
        self.textEdit_2 = QtWidgets.QTextEdit(Form)
        self.textEdit_2.setGeometry(QtCore.QRect(20, 180, 241, 101))
        self.textEdit_2.setObjectName("textEdit_2")

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "Form"))
        self.pushButton.setText(_translate("Form", "连接/开启"))
        self.pushButton_2.setText(_translate("Form", "发送"))
        self.lineEdit.setText(_translate("Form", "发送"))
        self.lineEdit_2.setText(_translate("Form", "接收"))
        self.radioButton.setText(_translate("Form", "客户端"))
        self.radioButton_2.setText(_translate("Form", "服务端"))
        self.label.setText(_translate("Form", "ip地址"))
        self.label_2.setToolTip(_translate("Form", "<html><head/><body><p align=\"center\"><br/></p></body></html>"))
        self.label_2.setText(_translate("Form", "端口"))

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    Form = QtWidgets.QWidget()
    ui = Ui_Form()
    ui.setupUi(Form)
    Form.show()
    sys.exit(app.exec_())

思路:

1.使用PyQT和Socket库

先初始化ui界面:

class Window(QWidget,Ui_Form):
    def __init__(self, parent=None, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)
        self.setupUi(self)
        ipaddress = Socket_Client.get_ip() #获取ip
        self.lineEdit_3.setText(ipaddress)
        self.radioButton.setChecked(True)
        self.lineEdit_4.setText("8888")
        self.pushButton.clicked.connect(self.socket_connect)
        self.pushButton_2.clicked.connect(self.send_message)
        self.radioButton.toggled.connect(self.switch_client_server)

然后绑定两个按钮的点击信号的槽函数:

	self.pushButton.clicked.connect(self.socket_connect)
  self.pushButton_2.clicked.connect(self.send_message)

创建socket类当运行槽函数时创建服务端或客户端:

class Socket_Client(object):
    def __init__(self,ipadress,port): #当类初始化时填入ip地址和端口号
        self.ipaddress = ipadress
        self.port = port

    @classmethod
    def get_ip(cls): #获取初始化的ip地址,获取不到填入127.0.0.1
        socket_ip = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        try:
            socket_ip.connect(('10.255.255.255', 1))
            return socket_ip.getsockname()[0]
        except Exception:
            return '127.0.0.1'
        finally:
            socket_ip.close()

    def client_socket(self):  #创建客户端的socket通信
        self.client_connect = socket.socket(family=-1,type=-1)
        self.client_connect.connect((self.ipaddress,self.port))

    def close_socket(self):   #关闭socket连接
        self.client_connect.close()

    def server_socket(self): #创建服务端的sockett通信
        self.server_connect = socket.socket(family=-1,type=-1)
        self.server_connect.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
        self.server_connect.bind((self.ipaddress,self.port))
        self.server_connect.listen(128)

    def server_accept(self):#服务端的监听函数
        self.client,self.client_ip_port = self.server_connect.accept()

    def server_send_data(self,data): #服务端发送函数
        data = data.encode('gbk')
        print(data)
        self.client.send(data)

    def send_data(self,data):#客户端发送数据函数
        data = data.encode('gbk')  #进行gbk编码
        print(data)
        self.client_connect.send(data)

    def recv_data(self):#客户端监听函数
        recv = str(self.client_connect.recv(1024),'gbk') #以gbk方式转码
        return recv

分别创建客户端和服务端的发送按钮和开启按钮的槽函数:

def socket_connect(self): #连接按钮绑定函数,建立socket连接
        QCoreApplication.processEvents();
        try:
            self.socket_client = Socket_Client(self.lineEdit_3.text(),int(self.lineEdit_4.text()))
            self.socket_client.client_socket()
            self.setWindowTitle("聊天程序1.0 连接成功")
            self.thread_1 = Thread_recv(self.socket_client,self.textEdit_2 #创建子进程
            self.thread_1.start()#开启子进程
        except Exception as e:
            print(e)
            print("error")
            self.setWindowTitle("聊天程序1.0 连接失败")

    def socket_server(self):  #服务端函数
        QCoreApplication.processEvents();
        try:
            self.server_socket = Socket_Client(self.lineEdit_3.text(),int(self.lineEdit_4.text()))
            self.server_socket.server_socket()
            self.setWindowTitle("聊天程序1.0 服务开启成功")
            self.thread_2 = Thread_sev(self.server_socket,self.textEdit_2) #创建子进程
            self.thread_2.start() #开启子进程
        except Exception as e:
            print(e)
            self.setWindowTitle("聊天程序1.0 服务开启失败")

    def send_message(self):#发送消息

        try:
            self.socket_client.send_data(self.textEdit.toPlainText())
            localtime = time.strftime("%H:%M:%S")
            self.textEdit_2.append(f"[{localtime}]:"+"发送成功!") 
            self.textEdit_2.append(f"[{localtime}]:" + "我说:" + self.textEdit.toPlainText() )
            self.textEdit.clear()
            self.textEdit.moveCursor(QTextCursor.End)
        except Exception as e:
            print(e)

    def server_send_data(self):
        try:
            self.server_socket.server_send_data(self.textEdit.toPlainText())
            localtime = time.strftime("%H:%M:%S")
            self.textEdit_2.append(f"[{localtime}]:" + "发送成功!")
            self.textEdit_2.append(f"[{localtime}]:" + "我说:" + self.textEdit.toPlainText())
            self.textEdit.clear()
            self.textEdit.moveCursor(QTextCursor.End)
        except Exception as e:
            print(e)

然后创建俩个QT线程,因为PYQT主线程用来绘制GUI界面,如果有创造一些耗时的函数,在主线程中执行,那么界面很容易就卡死,解决的方法一般有两个,一个是创造线程,进程,一个就是调用QCoreApplication.processEvents(),来让GUI界面防止卡死,但是遇到阻塞函数,还是一样会卡死。在socket中的接收消息的过程中,就需要一直等待接收,只能放到子线程中去执行。

class Thread_recv(QThread):  #客户端等待接收消息的线程
    def __init__(self, recv,text_edit):
        super().__init__()
        self.recv = recv
        self.text_edit = text_edit

    def run(self):
        while True:
            self.recv_data = self.recv.recv_data()
            print(self.recv_data)
            localtime = time.strftime("%H:%M:%S")
            self.text_edit.append( f"[{localtime}]:" +"对方说:"+ self.recv_data)

class Thread_sev(QThread):  #服务端等待连接的线程
    def __init__(self,server_socket,text_edit):
        super().__init__()
        self.server = server_socket
        self.text = text_edit

    def run(self):
        self.server.server_accept()
        print(self.server.client_ip_port)
        localtime = time.strftime("%H:%M:%S")
        self.text.append(f"[{localtime}]:" + f"客户端连接成功:{self.server.client_ip_port[0]}")
        while True:
            self.data = str(self.server.client.recv(1024),"gbk")
            print(self.data)
            localtime = time.strftime("%H:%M:%S")
            self.text.append(f"[{localtime}]:" + "对方说:" + self.data)

最后加一个选择按钮的切换状态槽函数和主函数:

def switch_client_server(self):
        print("switch")
        self.pushButton.clicked.connect(self.socket_server)
        self.pushButton_2.clicked.connect(self.server_send_data)
if __name__ == '__main__':

    app = QApplication(sys.argv)
    window =   Window()
    window.setWindowTitle("聊天程序1.0")
    window.show()
    sys.exit(app.exec())

总结:

pyqt的界面非常容易卡死,所以在写程序的时候,多线程是必不可少的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值