QPlainTextEdit如何禁用Shift+左键选中文本仅保留自定义下划线格式
解决PySide2 QPlainTextEdit自定义行下划线与Shift点击冲突问题
核心问题点
- 事件过滤器处理完鼠标点击逻辑后未拦截事件,默认事件继续传播触发了QPlainTextEdit自带的文本选中效果
- 原
change_summary_block_format方法仅重置了全文档格式,未给目标区间的行应用下划线样式 - Shift点击的行存储逻辑不合理,多次点击会导致区间计算异常
修改后可直接运行的代码
#!/usr/bin/python3.6 from PySide2.QtCore import Qt, QEvent from PySide2.QtWidgets import QApplication from PySide2.QtGui import (QTextCharFormat, QBrush, QColor, QTextCursor) from PySide2.QtWidgets import (QPlainTextEdit, QMainWindow, QVBoxLayout, QWidget) import sys class Window(QMainWindow): def __init__(self, app): super().__init__() # 存储点击的起始行光标 self.start_cursor = None def create_widget(self): self.plain_textedit = QPlainTextEdit() self.plain_textedit.setLineWrapMode(QPlainTextEdit.NoWrap) self.plain_textedit.setStyleSheet( """QPlainTextEdit {font-size: 14pt; font-family: Courier;}""") self.plain_textedit.setMouseTracking(True) # 存储默认文本格式,用于重置样式 self.default_char_format = self.plain_textedit.currentCharFormat() self.plain_textedit.setCursorWidth(5) self.plain_textedit.viewport().installEventFilter(self) main_layout = QVBoxLayout() main_layout.addWidget(self.plain_textedit) self.window = QWidget() self.window.setLayout(main_layout) self.setCentralWidget(self.window) def eventFilter(self, obj, event): if obj is self.plain_textedit.viewport() and event.type() == QEvent.MouseButtonPress: if event.button() == Qt.LeftButton: # 获取点击位置对应的行光标 text_cursor = self.plain_textedit.cursorForPosition(event.pos()) modifiers = QApplication.keyboardModifiers() # 普通左键点击:记录起始行,仅给当前行加下划线 if modifiers != Qt.ShiftModifier: self.start_cursor = text_cursor # 先重置全文档格式 self.reset_all_format() # 给当前行加下划线 self.add_line_underline(text_cursor) # Shift+左键点击:计算区间,给范围内所有行加下划线 else: if self.start_cursor is None: # 首次点击就按Shift的话直接把当前行设为起始行 self.start_cursor = text_cursor self.reset_all_format() start_line = self.start_cursor.blockNumber() end_line = text_cursor.blockNumber() # 统一区间顺序 if start_line > end_line: start_line, end_line = end_line, start_line # 遍历区间所有行加下划线 for line_num in range(start_line, end_line + 1): block = self.plain_textedit.document().findBlockByLineNumber(line_num) line_cursor = QTextCursor(block) self.add_line_underline(line_cursor) # 拦截事件,不让默认处理逻辑触发文本选中 return True return super().eventFilter(obj, event) def reset_all_format(self): """重置全文档为默认格式""" cursor = self.plain_textedit.textCursor() cursor.select(QTextCursor.Document) cursor.setCharFormat(self.default_char_format) cursor.clearSelection() self.plain_textedit.setTextCursor(cursor) def add_line_underline(self, cursor): """给指定光标所在行添加蓝色下划线""" cursor.select(QTextCursor.LineUnderCursor) format = QTextCharFormat() format.setForeground(QBrush(QColor("blue"))) format.setUnderlineStyle(QTextCharFormat.SingleUnderline) cursor.mergeCharFormat(format) def main(): app = QApplication([]) window = Window(app) window.create_widget() window.show() app.exec_() if __name__ == "__main__": sys.exit(main())
关键修改说明
- 事件过滤器处理完鼠标点击逻辑后返回
True,拦截事件传播,彻底屏蔽默认的文本选中行为 - 优化了行区间计算逻辑,支持正选反选(Shift点击行在起始行上方也能正常计算区间)
- 拆分了重置格式、添加下划线的独立方法,逻辑更清晰
- 移除了冗余的import导入,减少不必要的资源占用
内容的提问来源于stack exchange,提问作者user765443
相关产品推荐
相关产品推荐

