本文仅为示例,用于参考,功能并不完整
主要实现以下功能:
1.重写PlainTextEdit组件实现类似微信ctrl+enter换行,enter发送信息操作
2.带头像的消息气泡创建
3.消息气泡的自适应大小
窗口布局(详细可以通过示例代码中的.ui进行查看)
代码获取地址
GitHub:PyQt5-Chat-Demo
百度网盘:https://pan.baidu.com/s/1Pi06nAeOo9sWiNaaHgC86w?pwd=ayhf
代码详解(请先获取代码方便对照)
1.窗口初始化与定义
主要操作:初始化,定义信号与槽
class MainWindow(QMainWindow,Ui_MainWindow):
def __init__(self,parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
self.sum=0 #气泡数量
self.widgetlist = [] #记录气泡
self.text = "" # 存储信息
self.icon = QtGui.QPixmap("1.jpg") # 头像
#设置聊天窗口样式 隐藏滚动条
self.scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
# 信号与槽
self.pushButton.clicked.connect(self.create_widget) #创建气泡
self.pushButton.clicked.connect(self.set_widget) #修改气泡长宽
self.plainTextEdit.undoAvailable.connect(self.Event) #监听输入框状态
scrollbar = self.scrollArea.verticalScrollBar()
scrollbar.rangeChanged.connect(self.adjustScrollToMaxValue) #监听窗口滚动条范围
2.回车发送的实现
用户回车->plainTextEdit声明于PlainTextEdit_Rewite.py的重写方法被激活->初始化函数的信号监听到->执行槽函数
主要操作:模拟发送点击事件(会导致TextEdit焦点消失),TextEdit重新设置焦点
# 回车绑定发送
def Event(self): #注意,这个方法是先通过了PlainTextEdit_Rewite.py的重写方法激活了上方代码的信号,才执行的槽函数
if not self.plainTextEdit.isEnabled(): #当PlainTextEdit处于禁用状态执行下面代码
self.plainTextEdit.setEnabled(True)
self.pushButton.click()
self.plainTextEdit.setFocus()
Qt5没有原生的回车发送的方法,试过很多方法,对比来看,用信号监听plainTextEdit的状态是最稳定且方便的
3.生成气泡并插入scrollArea
调用new_widget.py下set_return方法创建新组件并插入scrollArea
#创建气泡
def create_widget(self):
self.text=self.plainTextEdit.toPlainText()
self.plainTextEdit.setPlainText("")
self.sum += 1
if self.sum % 2: # 根据判断创建左右气泡
Set_question.set_return(self, self.icon, self.text,QtCore.Qt.LeftToRight) # 调用new_widget.py中方法生成左气泡
QApplication.processEvents() # 等待并处理主循环事件队列
else:
Set_question.set_return(self, self.icon, self.text,QtCore.Qt.RightToLeft) # 调用new_widget.py中方法生成右气泡
QApplication.processEvents() # 等待并处理主循环事件队列
窗口组件的层级关系请看上方窗口布局
4.修改气泡组件长宽
Qt5组件的更新方式比较奇怪,只有在气泡组件创建完成后才能获取到文本框适应的宽高,所以这里是在创建好后再进行修改,可以看到修改方式比较傻瓜,但起码效果还是能看的
# 修改气泡长宽
def set_widget(self):
font = QFont()
font.setPointSize(16)
fm = QFontMetrics(font)
text_width = fm.width(self.text)+115 #根据字体大小生成适合的气泡宽度
if self.sum != 0:
if text_width>632: #宽度上限
text_width=int(self.textBrowser.document().size().width())+100 #固定宽度
self.widget.setMinimumSize(text_width,int(self.textBrowser.document().size().height())+ 40) #规定气泡大小
self.widget.setMaximumSize(text_width,int(self.textBrowser.document().size().height())+ 40) #规定气泡大小
self.scrollArea.verticalScrollBar().setValue(10)
5.窗口自动滚动
信号监听窗口滚动条范围,执行此槽函数
# 窗口滚动到最底部
def adjustScrollToMaxValue(self):
scrollbar = self.scrollArea.verticalScrollBar()
scrollbar.setValue(scrollbar.maximum())
布局文件的改动(注意)
因为本示例重写了QPlainTextEdit,所以如果你通过PyUIC重新生成了布局文件,需要在布局文件中将组件的声明也修改掉。
PyUIC生成的代码
self.plainTextEdit = QtWidgets.QPlainTextEdit(self.centralwidget)
修改为
from PlainTextEdit_Rewite import MyPlainTextEdit
self.plainTextEdit = MyPlainTextEdit(self.frame)