PySide 查找功能大杂烩 基于文本编辑器(QPlainTextEdit)

#程序员成长:技术、职场与思维模式实战指南#

PySide 查找功能大杂烩 基于文本编辑器(QPlainTextEdit)

实现功能一览
  • 向上或向下查找
  • 区分大小写
  • 匹配完整单词
  • 循环
  • 向上或向下与其他的组合
技术问题

在前几篇文章中存在如下问题:

  1. 使用文本编辑器的文档方法(QPlainTextEdit.document)返回的文本文档(QTextDocumet)的查找方法(find)返回的文本光标(QTextCursor)
  2. 借助文本编辑器的设置文本光标(QPlainTextEdit.setTextCursor)结合1的文本光标来实现查找功能

出现问题

看似一切都合乎情理之中,但是问题的出现往往是意想不到!就在我要实现循环功能的时候,我绞尽脑汁还是没有好的办法,好在天无绝人之路!我测试文本编辑(QPlainTextEdit)的时候意外发现他的查找符合我的需求!
于是以前写的代码好像小丑一样!明明你已经有轮子可用了,却非要绕一大圈。当然这也是PyQt\PySide这类文章或者书记少导致的。

反思

能使用当前对象的方法,就不要再深入其父类这样不仅加重了代码量还使得逻辑变得复杂!

看完下边的代码,你就知道我之前的代码有多么搞笑了!

代码

重要的

这篇文件以及关于PySide6的都是关于我写的一个记事本项目的实现!(仿照win10的记事本)!
代码是基于文本编辑器(QPlainTextEdit)但是也适合文本编辑(QTextEdit)

# coding = utf-8

from PySide6.QtWidgets import (QWidget,QVBoxLayout,QPlainTextEdit,QGroupBox,QRadioButton,QLineEdit,QPushButton,QCheckBox,
                               QApplication,QMessageBox)
from PySide6.QtCore import QRegularExpression
from PySide6.QtGui import QTextDocument,QTextCursor
import sys

class TestWidget(QWidget):
    def __init__(self):
        super().__init__()
        self.setupUi()
        self.setEventBind()

    def setupUi(self):
        """设置用户界面
        """
        self.setWindowTitle("查找下一个与是否区分大小写")

        # 主布局使用垂直盒子布局
        vboxLayout = QVBoxLayout(self)

        # 实例化 文本编辑器 查找行文本编辑器 查找下一个按钮 区分大小写复选框 
        self.plainTextEdit = QPlainTextEdit()
        self.findLineEdit = QLineEdit()

        # 方向 组合盒子
        self.directGroupBox = QGroupBox()
        self.directGroupBox.setTitle("方向")
        self.upButton = QRadioButton("向上(&U)")
        self.downButton = QRadioButton("向下(&D)")
        directVLayout = QVBoxLayout(self.directGroupBox)
        directVLayout.addWidget(self.upButton)
        directVLayout.addWidget(self.downButton)
        self.downButton.setChecked(True)

        self.caseSensitiveCheckBox = QCheckBox("区分大小写")
        self.findWordCheckBox = QCheckBox("匹配完整单词")
        self.cycleCheckBox = QCheckBox("循环")

        self.findPushBtn = QPushButton("查找下一个")

        # 添加控件到主布局
        vboxLayout.addWidget(self.plainTextEdit)
        vboxLayout.addWidget(self.findLineEdit)
        vboxLayout.addWidget(self.directGroupBox)
        vboxLayout.addWidget(self.caseSensitiveCheckBox)
        vboxLayout.addWidget(self.findWordCheckBox)
        vboxLayout.addWidget(self.cycleCheckBox)
        vboxLayout.addWidget(self.findPushBtn)

    def setEventBind(self):
        """设置事件绑定
        """
        self.findPushBtn.clicked.connect(self.setCursor)
        
    def getRadioBtnStat(self) -> tuple[bool,bool]:
        """获取按钮状态

        :return: 上一个与下一个按钮的点击状态 元组
        """
        return (self.upButton.isChecked(),self.downButton.isChecked())

    def getCheckBoxStat(self) -> tuple[bool,bool]:
        """获取复选框状态

        :return: 获取忽略大小写、匹配完整单词的勾选状态
        """
        return (self.caseSensitiveCheckBox.isChecked(),self.findWordCheckBox.isChecked())

    def getCycleCheckBoxStat(self) -> bool:
        """获取循环复选框的状态

        :return: True or False
        """
        return self.cycleCheckBox.isChecked()

    def getFindFlags(self):
        """获取查找标签 组合
        """
        # 查找标签 上一个 下一个 忽略大小写
        findPrev = QTextDocument.FindFlag.FindBackward
        findCase = QTextDocument.FindFlag.FindCaseSensitively
        findWord = QTextDocument.FindFlag.FindWholeWords

        # 通过按钮是否点击 以及 复选框是否勾选 来返回flags
        prevBtnStat,nextBtnStat = self.getRadioBtnStat()
        caseBoxStat,wordBoxStat= self.getCheckBoxStat()

        if nextBtnStat:
            flags = 0
            if caseBoxStat and wordBoxStat:
                flags = findCase | findWord
            elif caseBoxStat:
                flags = findCase
            elif wordBoxStat:
                flags = findWord
        elif prevBtnStat:
            flags = findPrev
            if caseBoxStat and wordBoxStat:
                flags = findPrev | findCase | findWord
            elif caseBoxStat:
                flags = findPrev | findCase
            elif wordBoxStat:
                flags = findPrev | findWord
        return flags

    def setCursor(self):
        """设置光标
        """
        # 使用QPlainTextEdit的find功能 配合QRegularExpression 传入查找标签的文本 
        # 再结合获取光标标签来实现
        findStr = self.findLineEdit.text()
        exp = QRegularExpression(findStr)
        flags = self.getFindFlags()
        if flags:
            findRes = self.plainTextEdit.find(exp,flags)
            self.isResetCursor(findRes)
        else:
            findRes = self.plainTextEdit.find(exp)
            self.isResetCursor(findRes)

    def setNoFindMsgBox(self,findResult:bool):
        """弹出找不到提示
        """
        if findResult == False:
            findStr = self.findLineEdit.text()
            # 提示窗口
            msgBox = QMessageBox(self)
            msgBox.setWindowTitle("记事本") #查找窗口太小 时不会显示
            msgBox.setIcon(QMessageBox.Icon.Information)
            msgBox.setText(f'"{findStr}"')
            msgBox.exec()

    def isResetCursor(self,findResult:bool):
        """重新设置光标
        """
        cycleStatus = self.getCycleCheckBoxStat()
        prevBtnStat,nextBtnStat = self.getRadioBtnStat()
        # 如果勾选 按钮为向上 从最后开始查找
        # 如果勾选 按钮为向下 从开头开始查找
        if cycleStatus:
            if prevBtnStat and findResult == False:
                self.plainTextEdit.moveCursor(QTextCursor.MoveOperation.End)
            elif nextBtnStat and findResult == False:
                self.plainTextEdit.moveCursor(QTextCursor.MoveOperation.Start)
        else:
            if findResult == False:
                self.setNoFindMsgBox(findResult)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    testWidget = TestWidget()
    testWidget.show()
    sys.exit(app.exec())
参考
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

开心-开心急了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值