PySide6 Win10记事本从零到一——第六章(下) 搜索、查找、替换等功能实现
本文摘要主要介绍了如何在PySide6中实现搜索、查找和替换功能。搜索功能通过QDesktopServices.openUrl()方法实现,利用Bing搜索引擎的URL参数传递选中文本进行搜索。查找功能则通过自定义PlainTextEdit类实现,包含查找上一个/下一个操作和查找对话框。实现时重点关注文本选中状态检测、剪贴板状态管理以及跨平台兼容性问题。代码示例展示了如何将菜单项与文本编辑器的信号
第六章(下) 搜索、查找、替换等功能实现
在这一部分我们会实现搜索功能,自定义查找对话框 用于查找。
6.4 搜索功能
PySide6对于访问常见的桌面服务的方法,有一个专门的类QDesktopServices,我们借助提供的openUrl方法就可以让其访问某个网页链接(如:www.baidu.com)。
学习过网络爬虫的读者可能会有所了解,搜索引擎其实就是一个具有参数的网址,当我们传入搜索词的时候 其实就实现了搜索功能。
注意:搜索引擎相关
6.4.1实现思路
实现思路 bing_search方法:
- 选中并获取选中文本内容
- 将选中文本内容传入
https://cn.bing.com/search?q=%s的%s中 - 使用
QDesktopServices.openUrl(f"https://cn.bing.com/search?q={select_text}")访问
重点:
- 获取文本:
QPlainTextEdit.textCursor().selectedText() - 使用Bing搜索按钮是否可用
setEnabled()与能否复制copyAvailable信号连接
注意:使用Bing搜索 按钮是否可用,其实是看是否有文本选中, 能否复制
copyAvailable就是这个逻辑
6.4.2 实现代码
custom_menu.py
from PySide6.QtWidgets import QMenu,QPlainTextEdit
from PySide6.QtGui import QKeySequence,QGuiApplication,QDesktopServices
class FileMenu(QMenu):
"""文件菜单
:param QMenu: PySide6 菜单类
"""
pass
class EditMenu(QMenu):
"""编辑菜单
:param QMenu: PySide6 菜单类
"""
def __init__(self):
"""初始化
"""
super().__init__()
self.setup_ui()
def setup_ui(self):
"""设置菜单项
"""
self.setTitle("编辑(&E)",)
self.undo = self.addAction("撤销(&U)",QKeySequence.StandardKey.Undo)
self.addSeparator()
self.cut = self.addAction("剪切(&T)",QKeySequence.StandardKey.Cut)
self.copy = self.addAction("复制(&C)",QKeySequence.StandardKey.Copy)
self.paste = self.addAction("粘贴(&P)",QKeySequence.StandardKey.Paste)
self.delete = self.addAction("删除(&L)",QKeySequence.StandardKey.Delete)
self.addSeparator()
self.search = self.addAction("使用Bing搜索")
find_ = self.addAction("查找(&F)",QKeySequence.StandardKey.Find)
find_next = self.addAction("查找下一个(&N)",QKeySequence.StandardKey.FindNext)
find_previous = self.addAction("查找上一个(&V)",QKeySequence.StandardKey.FindPrevious)
replace = self.addAction("替换(&R)",QKeySequence.StandardKey.Replace)
goto =self.addAction("转到(&G)","Ctrl+G")
self.addSeparator()
self.select_all = self.addAction("全选(&A)",QKeySequence.StandardKey.SelectAll)
date_ = self.addAction("时间/日期(&D)","F5")
# 默认状态 撤销、剪切、复制、粘贴、删除 、搜索不可用
self.undo.setEnabled(False)
self.cut.setEnabled(False)
self.copy.setEnabled(False)
self.paste.setEnabled(False)
self.delete.setEnabled(False)
self.search.setEnabled(False)
# 初始化剪贴板
self.clipbaord_ = QGuiApplication.clipboard()
def set_event_bind(self,plain_text_edit:QPlainTextEdit):
"""设置必应搜索
:param plain_text_edit: PySide6 QPlainTextEdit
"""
# 设置状态 撤销、剪切、复制、粘贴、删除、搜索
plain_text_edit.undoAvailable.connect(self.undo.setEnabled)
plain_text_edit.copyAvailable.connect(self.cut.setEnabled)
plain_text_edit.copyAvailable.connect(self.copy.setEnabled)
self.clipbaord_.dataChanged.connect(self.reset_paste_state)
plain_text_edit.copyAvailable.connect(self.delete.setEnabled)
plain_text_edit.copyAvailable.connect(self.search.setEnabled)
# 撤销、剪切、复制、粘贴、删除 、全选 搜索行为的绑定
self.undo.triggered.connect(plain_text_edit.undo)
self.cut.triggered.connect(plain_text_edit.cut)
self.copy.triggered.connect(plain_text_edit.copy)
self.paste.triggered.connect(plain_text_edit.paste)
self.delete.triggered.connect(plain_text_edit.clear)
self.select_all.triggered.connect(plain_text_edit.selectAll)
self.search.triggered.connect(lambda: self.bing_search(plain_text_edit))
def reset_paste_state(self):
"""重新设置粘贴状态
"""
clipbaord_text = self.clipbaord_.text()
if clipbaord_text:
self.paste.setEnabled(True)
else:
self.paste.setEnabled(False)
def bing_search(self,plain_text_edit:QPlainTextEdit):
"""Bing搜索
:param plain_text_edit: PySide6 QPlainTextEdit
"""
search_text = plain_text_edit.textCursor().selectedText()
QDesktopServices.openUrl(f"https://cn.bing.com/search?q={search_text}")
notepad_main.py没有变化,所以沿用上一个
6.4.3 实现效果
PySide6 搜索功能演示
waylang、x11、windows都一些区别:
- 没有打开默认浏览器: 都会直接打开浏览器并搜索
- 已经打开并最小化浏览器:
x11和windows都会再次弹出浏览器窗口,而wayland只是有提示弹窗 windows不会报错,x11提示缺少文件
6.5 查找相关
需要实现如下功能:
- 查找相关行为是否可用:查找、查找上一个、查找下一个
- 查找功能: 查找上一个与下一个
- 查找对话框: 结合查找功能
为了方便查找相关功能的实现,我们使用将自定义一个纯文本编辑类
6.5.1 查找行为是否可用
实现逻辑:
- 自定义一个信号,用于检测当文本改变时候是否有内容(空字符串也算)
- 当有内容则行为可用
实现代码:
custom_plain_text_edit.py
from PySide6.QtWidgets import QPlainTextEdit
from PySide6.QtCore import Signal
class PlainTextEdit(QPlainTextEdit):
"""纯文本编辑
:param QPlainTextEdit: PySide6 QPlainTextEdit
"""
hasText = Signal(bool)
def __init__(self):
"""初始化
"""
super().__init__()
# 基于文本改变 检测是否有内容
self.textChanged.connect(self.__has_text)
def __has_text(self):
"""判断是否有文本
:param plain_text_edit: 纯文本编辑
"""
self.hasText.emit(True) if self.toPlainText() else self.hasText.emit(False)
注意:信号必需声明为类变量;借助文本改变信号来判断文本内容是否为空,并发送信号
notepad_main.py:删除导入QPlainTextEdit添加导入from custom_plain_text_edit import PlainTextEdit;修改QPlainTextEdit() 为PlainTextEdit()
custom_menu.py
from PySide6.QtWidgets import QMenu
from PySide6.QtGui import QKeySequence,QGuiApplication,QDesktopServices
from custom_plain_text_edit import PlainTextEdit
class FileMenu(QMenu):
"""文件菜单
:param QMenu: PySide6 菜单类
"""
pass
class EditMenu(QMenu):
"""编辑菜单
:param QMenu: PySide6 菜单类
"""
def __init__(self):
"""初始化
"""
super().__init__()
self.setup_ui()
def setup_ui(self):
"""设置菜单项
"""
self.setTitle("编辑(&E)",)
self.undo = self.addAction("撤销(&U)",QKeySequence.StandardKey.Undo)
self.addSeparator()
self.cut = self.addAction("剪切(&T)",QKeySequence.StandardKey.Cut)
self.copy = self.addAction("复制(&C)",QKeySequence.StandardKey.Copy)
self.paste = self.addAction("粘贴(&P)",QKeySequence.StandardKey.Paste)
self.delete = self.addAction("删除(&L)",QKeySequence.StandardKey.Delete)
self.addSeparator()
self.search = self.addAction("使用Bing搜索")
self.find_ = self.addAction("查找(&F)",QKeySequence.StandardKey.Find)
self.find_next = self.addAction("查找下一个(&N)",QKeySequence.StandardKey.FindNext)
self.find_previous = self.addAction("查找上一个(&V)",QKeySequence.StandardKey.FindPrevious)
replace = self.addAction("替换(&R)",QKeySequence.StandardKey.Replace)
goto =self.addAction("转到(&G)","Ctrl+G")
self.addSeparator()
self.select_all = self.addAction("全选(&A)",QKeySequence.StandardKey.SelectAll)
date_ = self.addAction("时间/日期(&D)","F5")
# 默认状态 撤销、剪切、复制、粘贴、删除 、搜索、查找、查找上一个、查找下一个 不可用
self.undo.setEnabled(False)
self.cut.setEnabled(False)
self.copy.setEnabled(False)
self.paste.setEnabled(False)
self.delete.setEnabled(False)
self.search.setEnabled(False)
self.find_.setEnabled(False)
self.find_next.setEnabled(False)
self.find_previous.setEnabled(False)
# 初始化剪贴板
self.clipbaord_ = QGuiApplication.clipboard()
def set_event_bind(self,plain_text_edit:PlainTextEdit):
"""设置必应搜索
:param plain_text_edit: PySide6 QPlainTextEdit
"""
# 设置状态 撤销、剪切、复制、粘贴、删除、搜索、查找、查找下一个、查找上一个
plain_text_edit.undoAvailable.connect(self.undo.setEnabled)
plain_text_edit.copyAvailable.connect(self.cut.setEnabled)
plain_text_edit.copyAvailable.connect(self.copy.setEnabled)
self.clipbaord_.dataChanged.connect(self.reset_paste_state)
plain_text_edit.copyAvailable.connect(self.delete.setEnabled)
plain_text_edit.copyAvailable.connect(self.search.setEnabled)
plain_text_edit.hasText.connect(self.find_.setEnabled)
plain_text_edit.hasText.connect(self.find_next.setEnabled)
plain_text_edit.hasText.connect(self.find_previous.setEnabled)
# 撤销、剪切、复制、粘贴、删除 、全选 搜索行为的绑定
self.undo.triggered.connect(plain_text_edit.undo)
self.cut.triggered.connect(plain_text_edit.cut)
self.copy.triggered.connect(plain_text_edit.copy)
self.paste.triggered.connect(plain_text_edit.paste)
self.delete.triggered.connect(plain_text_edit.clear)
self.select_all.triggered.connect(plain_text_edit.selectAll)
self.search.triggered.connect(lambda: self.bing_search(plain_text_edit))
def reset_paste_state(self):
"""重新设置粘贴状态
"""
clipbaord_text = self.clipbaord_.text()
if clipbaord_text:
self.paste.setEnabled(True)
else:
self.paste.setEnabled(False)
def bing_search(self,plain_text_edit:PlainTextEdit):
"""Bing搜索
:param plain_text_edit: PySide6 QPlainTextEdit
"""
search_text = plain_text_edit.textCursor().selectedText()
QDesktopServices.openUrl(f"https://cn.bing.com/search?q={search_text}")
6.5.2 查找对话框与查找功能
未完待续
6.6 替换与转到
未完待续
6.7 插入日期时间
这里会插入一个类似16:21 2025/11/02的时间格式
6.7.1 实现逻辑与代码
实现逻辑
- 借助
QDateTime.currentDateTime()获取当前时间 - 将获取的时间转为需要的格式
- 插入该时间格式到文本编辑中
注意:使用的是自定义时间格式
hh:mm yyyy/MM/dd,hh:24小时;mm:60分钟;yyyy:年份;MM:月份;dd:日;
custom_plain_text_edit.py 添加如下方法:
def insert_date_time(self):
"""插入日期时间
"""
currentDateTime = QDateTime.currentDateTime()
formattedTime = currentDateTime.toString("hh:mm yyyy/MM/dd")
self.plainTextEdit.insertPlainText(formattedTime)
custom_menu.py添加如下:
self.date_ .triggered.connect(plain_text_edit.insert_date_time)
更多推荐


所有评论(0)