PySide 查找功能大杂烩 基于文本编辑器(QPlainTextEdit)
实现功能一览
- 向上或向下查找
- 区分大小写
- 匹配完整单词
- 循环
- 向上或向下与其他的组合
技术问题
在前几篇文章中存在如下问题:
- 使用文本编辑器的文档方法(QPlainTextEdit.document)返回的文本文档(QTextDocumet)的查找方法(find)返回的文本光标(QTextCursor)
- 借助文本编辑器的设置文本光标(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())
参考
- 建议先看重构版
PySide6专栏