PyQt简单示例聊天程序
效果展示:
代码:
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())
界面示意图:
界面代码:
# -*- 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的界面非常容易卡死,所以在写程序的时候,多线程是必不可少的。