【PyQt】基于QTextEdit为自己的文本框添加额外的功能(滚轮缩放、关键词搜索等)

【未经个人允许不得私自转载!】
【文章发布于CSDN。原文链接:https://blog.csdn.net/weixin_44733774/article/details/124519858




【功能】

  • 滚轮缩放文本(可禁止)
  • 文本单行模式(强制单行输入,可禁止)
  • 回车发送文本(可禁止)
  • 搜索关键词


【运行图】








代码

组件可以直接使用,请放心食用。(不爽xj的可以把类名改掉,但如果完全照搬代码的话最好注明来源,这是做人的最低底线。

import sys
from PyQt5.QtWidgets import QWidget,QTextEdit,QApplication
from PyQt5.QtGui import QTextCursor,QFont,QTextOption
from PyQt5.QtCore import Qt,pyqtSignal



class XJ_TextEdit(QTextEdit):
    textSent=pyqtSignal(str)#槽信号,当发送文本时发送信号
    #textChanged,为自带的槽信号,文本内容更改时触发
    def __init__(self,parent=None):
        super(XJ_TextEdit, self).__init__(parent)
        self.__oneLineMode=False
        self.__sendMsgMode=True
        self.setFont(QFont(self.font().family(),12))#简单设置下字体,初始字体的字号太小了
        self.__allowScale=False
        
    def OneLineMode(self,flag:bool):#单行模式,文本内容将只保留最后一行字串,并且窗口大小修改为单行大小,按回车将不会换行
        self.__oneLineMode=flag
        if(flag):#如果是单行模式那么就去设置下文本(多行文本将只留下最后一行
            self.__SetOneLineText()

        #对组件的模式策略进行设置
        height=self.__GetLineHeight()
        if(flag):#如果为单行模式,取消“自动换行”,并且把滚动条全隐藏
            self.setWordWrapMode(QTextOption.NoWrap)#设置换行模式为“不自动换行”
            self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)#隐藏行滚动条
            self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)#隐藏纵滚动条
            self.setMinimumHeight(height)
            self.setMaximumHeight(height)
        else:#多行模式则把“自动换行”恢复,并且显示滚动条
            self.setWordWrapMode(QTextOption.WrapAtWordBoundaryOrAnywhere)#设置换行模式为默认的“智能换行”
            self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)#显示行滚动条
            self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)#显示纵滚动条
            self.setMinimumHeight(height)
            self.setMaximumHeight(QApplication.desktop().screenGeometry().height())

    def keyPressEvent(self, event):#键盘某个键被按下时调用
        enter=(event.key()==Qt.Key_Return or event.key()==Qt.Key_Enter)#回车键
        ctrl=event.modifiers()==Qt.ControlModifier#ctrl键

        if(enter):#按下回车键
            if(self.__sendMsgMode):#如果设置了信息发送模式
                if(self.__oneLineMode or ctrl):#单行模式按【回车】触发;多行模式按【ctrl+回车】触发
                    self.textSent.emit(self.toPlainText())#触发文本发送信号
                    self.setText("")#清除文本
            return
        if(self.__oneLineMode and ctrl and event.key()==Qt.Key_V):#如果是单行模式的话,在按下Ctrl+V进行文本粘贴时只会保留最后一行文本
            cursor = self.textCursor()#光标(为了插入文本
            data=QApplication.clipboard().mimeData()#剪切板内的数据
            if(data.hasHtml()):
                cursor.insertHtml(data.html())
            elif(data.hasText()):
                cursor.insertText(data.text())
            self.__SetOneLineText()#设置文本
            return
        super().keyPressEvent(event)#没有触发文本发送文本粘贴时该干啥干啥

    def Search(self,keyword):#搜索关键词,搜索成功将会高亮文本,并且返回True,否则返回False
        cursor = self.textCursor()#光标
        text=self.toPlainText()#文本内容
        L=text.find(keyword,cursor.position())#在光标位置作为起点开始寻找
        if(L==-1):
            L=text.find(keyword)#从头开始寻找
            if(L==-1):
                return False
        R=L+len(keyword)
        cursor.setPosition(L,QTextCursor.MoveAnchor)#移动光标
        cursor.setPosition(R,QTextCursor.KeepAnchor)#拖动光标
        self.setTextCursor(cursor)
        return True

    def wheelEvent(self, event):#重写滚轮事件
        if(self.__allowScale and event.modifiers()==Qt.ControlModifier):#允许缩放为真,并且按下了Ctrl键,则进行缩放
            self.zoomIn(1 if event.angleDelta().y()>0 else -1)#调用zoomIn进行缩放
            if(self.__oneLineMode):#如果是单行模式的话还得把控件高度调一下
                height=self.__GetLineHeight()
                self.setMinimumHeight(height)
                self.setMaximumHeight(height)
            return
        __wheel_V=self.verticalScrollBar()#纵滚动条
        __wheel_V.setValue(__wheel_V.value()-event.angleDelta().y())#因为默认的文本编辑框在只读模式下时按下Ctrl+滚轮是会缩放的,所以滚轮事件不能交给super().wheelEvent

    def AllowWheelScale(self,flag):#是否允许滚轮缩放。当该值为真时使用Ctrl+滚轮即可缩放
        self.__allowScale=flag
    def SendMsgMode(self,flag:bool):#文本发送模式,如果为真那么按下回车键(多行模式还得同时按下Ctrl)时将会清除文本内容并且触发textSent信号
        self.__sendMsgMode=flag
        
    def __GetLineHeight(self):#获取单行字串的最低高度
        return self.fontMetrics().lineSpacing()+10#10是魔法数字,非常恶意,是一点一点试出来的。不知道这个“10”是哪个参数设置的,一直没找到,而且在文本缩放非常极端的时候这个“10”的效果不会很好
    def __SetOneLineText(self):#设置单行文本(只保留最后一行的文本)
        text=self.toPlainText()
        sep=text.find('\n')+1#寻找回车符的后一个字符
        cursor = self.textCursor()#光标
        offset=len(text)-cursor.position()#距离文末的偏移量

        while(sep):
            if(self.__sendMsgMode):#如果可以发送文本
                self.textSent.emit(text[:sep])#连同回车符也一并发送
            text=text[sep:]#新行内容
            sep=text.find('\n')+1#寻找回车符的后一个字符
        self.setText(text)
        offset=len(text)-offset#距离文首的偏移量(此时文本仅一行
        if offset<0:
            offset=0
        cursor.setPosition(offset,QTextCursor.MoveAnchor)#移动光标
        self.setTextCursor(cursor)
        
if __name__ == '__main__':
    app = QApplication(sys.argv)


    te=XJ_TextEdit()
    te.append('<font color="red"> RRR </font>')#给文本加点料
    te.append("123456789\nABCDEFGHI\n123456789")
    te.append('<font color="green"> GGG </font>')
    te.Search("456")#搜索文本
    te.Search("456")
    te.setFont(QFont('楷体',20))#设置字体
    te.SendMsgMode(True)#发送文本
    te.textSent.connect(lambda s:print("【文本发送】\n",s))#设置“发送文本”的回调函数
#    te.setReadOnly(True)#设置为只读
    te.OneLineMode(True)#单行模式
    te.AllowWheelScale(True)#Ctrl+滚轮的文本缩放
    te.show()

    sys.exit(app.exec())




其中“粘贴文本”的操作参考了【Python剪切板提取、截图、图片粘贴,操作汇总 】(关键词:"QApplication.clipboard")

“文本缩放”参考了【PyQT 5 QTextEdit实现Ctrl+鼠标滚动放大或缩小文本】(虽然他代码不怎么用但至少让我知道了有QTextEdit.zoomIn这个函数)

猜你喜欢

转载自blog.csdn.net/weixin_44733774/article/details/124519858