战前准备

  • github以及它的访问权限
  • 强大的心理支撑
  • 一点点英文水平(至少会念ABC )
  • 会写测试样例
  • 面向对象要学好(没学真的会感到是在地狱)

使用环境

  • python 3.8.0
  • pyqt 5.15.9
  • pycharm 2021.3

基础类

基本上在这两个类反复横跳

  • QsciScintilla
  • QTextEdit

手册或者参考

QTextEdit的应用
这是我的小小爹
QsciScintilla的应用
这是大爹但又没完全是

QTextEdit

跟着github上的代码走就没问题…

import sys
from PyQt5.QtCore import QRegExp
from PyQt5.QtGui import QColor, QTextCharFormat, QFont, QSyntaxHighlighter## 不用QS的...
def format(color, style=''):"""Return a QTextCharFormat with the given attributes."""_color = QColor()if type(color) is not str:_color.setRgb(color[0], color[1], color[2])else:_color.setNamedColor(color)_format = QTextCharFormat()_format.setForeground(_color)if 'bold' in style:_format.setFontWeight(QFont.Bold)if 'italic' in style:_format.setFontItalic(True)return _formatSTYLES = {'header': format([0, 128, 0]),  # 头文件'd_header': format([60,179,113]),  # 头文件'keyword': format('#2E8B57', 'bold'),'operator': format([255, 140, 0]),  # 运算符'brace': format([255, 140, 0]),  # 符号'defclass': format([0, 80, 50], 'bold'),  # 类名'string': format([132, 26, 138]),  # 字符串'string2': format([132, 26, 138]),  # 字符串'comment': format([107, 147, 186]),  # 注释'self': format([150, 85, 140], 'italic'),  # 自身'numbers': format([42, 0, 255]),  # 数字'constant': format([202, 0, 202], 'bold'),  # 常量'deprecated': format([123, 23, 43], 'bold underline'),  # 弃用的成员'enums': format([128, 0, 255]),  # 枚举'fields': format([128, 0, 128]),  # 变量'return': format([255, 0, 85], 'bold'),  # return关键字'method_decl': format([255, 128, 64], 'bold'),  # 方法定义'method': format([0, 48, 96]),  # 方法'others': format([78, 123, 0]),  # 其他'static_fields': format([33, 0, 189], 'bold'),  # 静态变量
}class CppHighlighter(QSyntaxHighlighter):"""Syntax highlighter for the C/C++ language."""# headerheader = ['stdio.h', 'stdlib.h', 'math.h', 'string.h', 'time.h', 'ctype.h','stdbool.h', 'assert.h', 'limits.h', 'float.h', 'stddef.h', 'errno.h','signal.h', 'setjmp.h', 'stdarg.h', 'locale.h', 'wchar.h', 'time.h','unistd.h', 'fcntl.h', 'sys/types.h', 'sys/stat.h', 'dirent.h','pthread.h', 'semaphore.h', 'sys/socket.h', 'netinet/in.h','arpa/inet.h', 'netdb.h', 'sys/time.h', 'sys/wait.h']# C/C++ keywordskeywords = ['auto', 'break', 'case', 'char', 'const', 'continue', 'default', 'do','double', 'else', 'enum', 'extern', 'float', 'for', 'goto', 'if', 'int','long', 'register', 'return', 'short', 'signed', 'sizeof', 'static','struct', 'switch', 'typedef', 'union', 'unsigned', 'void', 'volatile','while', 'bool', 'catch', 'class', 'const_cast', 'delete', 'dynamic_cast','explicit', 'false', 'friend', 'inline', 'mutable', 'namespace', 'new','operator', 'private', 'protected', 'public', 'reinterpret_cast','static_cast', 'template', 'this', 'throw', 'true', 'try', 'typeid','typename', 'using', 'virtual', 'wchar_t',]# C/C++ operatorsoperators = ['=',# Comparison'==', '!=', '<', '<=', '>', '>=',# Arithmetic'\+', '-', '\*', '/', '//', '\%', '\*\*',# In-place'\+=', '-=', '\*=', '/=', '\%=',# Bitwise'\^', '\|', '\&', '\~', '>>', '<<',]# C/C++ bracesbraces = ['\{', '\}', '\(', '\)', '\[', '\]',]def __init__(self, document):QSyntaxHighlighter.__init__(self, document)rules = []# Header rules: #include<XX.h>header_rules1 = [('#include\s*<{}>'.format(a), 0, STYLES['header'])for a in CppHighlighter.header]# Header rules: #include "XXX.h"header_rules2 = [(r'#include\s*"([^"]+)"', 0, STYLES['d_header']),]rules += [(r'\b%s\b' % w, 0, STYLES['keyword'])for w in CppHighlighter.keywords]# print(rules)rules += [(r'%s' % o, 0, STYLES['operator'])for o in CppHighlighter.operators]rules += [(r'%s' % b, 0, STYLES['brace'])for b in CppHighlighter.braces]# All other rulesrules += [# 'self'(r'\bself\b', 0, STYLES['self']),# Double-quoted string, possibly containing escape sequences(r'"[^"\\]*(\\.[^"\\]*)*"', 0, STYLES['string']),# Single-quoted string, possibly containing escape sequences(r"'[^'\\]*(\\.[^'\\]*)*'", 0, STYLES['string2']),# 'def' followed by an identifier(r'\bdef\b\s*(\w+)', 1, STYLES['defclass']),# 'class' followed by an identifier(r'\bclass\b\s*(\w+)', 1, STYLES['defclass']),# From '#' until a newline(r'#[^\n]*', 0, STYLES['comment']),# Numeric literals(r'\b[+-]?[0-9]+[lL]?\b', 0, STYLES['numbers']),(r'\b[+-]?0[xX][0-9A-Fa-f]+[lL]?\b', 0, STYLES['numbers']),(r'\b[+-]?[0-9]+(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\b', 0,STYLES['numbers']),]rules += header_rules1rules += header_rules2self.rules = [(QRegExp(pat), index, fmt)for (pat, index, fmt) in rules]def highlightBlock(self, text):for expression, nth, format in self.rules:index = expression.indexIn(text, 0)while index >= 0:# We actually want the index of the nth matchindex = expression.pos(nth) + expression.cap(nth).index(expression.cap(nth))length = len(expression.cap(nth))self.setFormat(index, length, format)index = expression.indexIn(text, index + length)self.setCurrentBlockState(0)if __name__ == "__main__":from PyQt5 import QtWidgetsapp = QtWidgets.QApplication([])editor = QtWidgets.QPlainTextEdit()editor.setStyleSheet("""QPlainTextEdit{font-family:'Consolas'; background-color: rgb(204,232,207);}""")highlight = CppHighlighter(editor.document())editor.show()# Load sample.cpp into the editor for demo purposesinfile = open('your_file_path', 'r', encoding='utf-8')editor.setPlainText(infile.read())app.exec_()

QsciScintilla

全部重写

你没看错全部重写…

  1. QsciScintilla类重写动作
class MeQsciScintilla(QsciScintilla):# 继承编辑器类 重写键盘按键方法def __init__(self, parent=None):super(MeQsciScintilla, self).__init__(parent)def keyPressEvent(self, e):''' 测试按下按键 '''if e.key() == Qt.Key_Escape:passsuper().keyPressEvent(e)def wheelEvent(self, e):''' Ctrl + 滚轮 控制字体缩放 '''if e.modifiers() == Qt.ControlModifier:da = e.angleDelta()if da.y() > 0:self.zoomIn(1)  # QsciScintilla 自带缩放elif da.y() < 0:self.zoomOut(1)else:super().wheelEvent(e)
  1. LexerCustom类重写高亮和自动补全
class MeLexer(QsciLexerCustom):def __init__(self, parent):super(MeLexer, self).__init__(parent)# 父类是编辑器# 设置默认颜色# 设置默认背景# 设置默认字号self.setDefaultColor(QColor("#ff000000"))self.setDefaultPaper(QColor("#CCE8CF"))  # 背景 豆沙绿self.setDefaultFont(QFont("Consolas", 13))# 样式表 0-1-2-3-4-5# 0: 关键字 1: 运算符 2: 格式符 3: 数字 4: 默认 5: 注释# 颜色self.setColor(QColor("#3CB371"), 0)self.setColor(QColor("#6A5ACD"), 1)self.setColor(QColor("#20B2AA"), 2)self.setColor(QColor("#4169E1"), 3)self.setColor(QColor("#2D7C7F"), 4)self.setColor(QColor("#C0C0C0"), 5)# 字体 consolas DevC++的默认字体 字号自定self.setFont(QFont("Consolas", 13, weight=QFont.Bold), 0)self.setFont(QFont("Consolas", 13, weight=QFont.Bold), 1)self.setFont(QFont("Consolas", 13, weight=QFont.Bold), 2)self.setFont(QFont("Consolas", 13, weight=QFont.Bold), 3)self.setFont(QFont("Consolas", 13, weight=QFont.Bold), 4)self.setFont(QFont("Consolas", 13), 5)self.font(5).setItalic(True)# 定义关键词列表self.keywords_list = ['auto', 'break', 'case', 'char', 'const', 'continue', 'default', 'do','double', 'else', 'enum', 'extern', 'float', 'for', 'goto', 'if', 'int','long', 'register', 'return', 'short', 'signed', 'sizeof', 'static','struct', 'switch', 'typedef', 'union', 'unsigned', 'void', 'volatile','while', 'bool', 'catch', 'class', 'const_cast', 'delete', 'dynamic_cast','explicit', 'false', 'friend', 'inline', 'mutable', 'namespace', 'new','operator', 'private', 'protected', 'public', 'reinterpret_cast','static_cast', 'template', 'this', 'throw', 'true', 'try', 'typeid','typename', 'using', 'virtual', 'wchar_t', 'include', 'std',"byte", "word", "dword","int8_t", "uint8_t", "int16_t", "uint16_t","int32_t", "uint32_t", "int64_t", "uint64_t","int8", "uint8", "int16", "uint16","int32", "uint32", "int64", "uint64"]# 定义运算符列表self.operator_list = ['=',# Comparison'==', '!=', '<', '<=', '>', '>=',# Arithmetic'+', '-', '*', '/', '%',# In-place'+=', '-=', '*=', '/=', '%=',# Bitwise'^', '|', '&', '~', '>>', '<<', '"', '%s', '%f', '%d', '%ld']# 定义格式符列表self.format_list = ['{', '}', '(', ')', '[', ']', '#', ';', ',']def description(self, style):if style == 0:return "keyword_style"elif style == 1:return "operate_style"elif style == 2:return "format_style"elif style == 3:return "number_style"elif style == 4:return "default_style"elif style == 5:return "tips_style"### 无需返回值 但需要定义内容return ""def styleText(self, start, end):# 1. 初始化风格类self.startStyling(start)# 2. 切片数据text = self.parent().text()[start:end]# 3. 词法分析p = re.compile(r"\*\/|\/\*|//.*?(?=\r?\n|$)|\s+|\w+|\W")  # // and /**/# 关键词列表里是这样的元组  (token_name, token_len) :(关键词内容,关键词长度)token_list = [(token, len(bytearray(token, "utf-8"))) for token in p.findall(text)]# 4. 风格化# 4.1 分支multiline_comm_flag = Falseeditor = self.parent()if start > 0:previous_style_nr = editor.SendScintilla(editor.SCI_GETSTYLEAT, start - 1)if previous_style_nr == 3:multiline_comm_flag = True# 4.2 循环风格化for i, token in enumerate(token_list):if multiline_comm_flag:# 处于块注释状态,使用样式5进行风格化self.setStyling(token[1], 5)if token[0] == "*/":multiline_comm_flag = Falseelif token[0].startswith("//"):line_number = self.parent().SendScintilla(self.parent().SCI_LINEFROMPOSITION, start)line_start = self.parent().SendScintilla(self.parent().SCI_POSITIONFROMLINE, line_number)line_end = self.parent().SendScintilla(self.parent().SCI_GETLINEENDPOSITION, line_number)self.startStyling(line_start)self.setStyling(line_end - line_start + 1, 5)break  # 结束循环,不再继续处理该行后面的内容else:# 其他情况根据关键词、运算符、格式符、数字进行风格化if token[0] in self.keywords_list:self.setStyling(token[1], 0)elif token[0] in self.operator_list:self.setStyling(token[1], 1)elif token[0] in self.format_list:self.setStyling(token[1], 2)elif token[0].isdigit():self.setStyling(token[1], 3)elif token[0] == "/*":multiline_comm_flag = Trueself.setStyling(token[1], 5)else:self.setStyling(token[1], 4)
  1. TextEditorWidget类,重写QWidget类,隐藏上面两个重写类,并写交互接口
class TextEditorWidget(QWidget):gotoDeclarationSign = QtCore.pyqtSignal()gotoDefinitionSign = QtCore.pyqtSignal()gotoCallExpressSign = QtCore.pyqtSignal()def __init__(self, filename, filepath):super(TextEditorWidget, self).__init__(parent=None)# 配置config_obj = Config()self.config_ini = config_obj.read_config()# 可访问成员变量self.filename = filenameself.filepath = filepathself.status = False# 创建布局self.__layout = QVBoxLayout(self)self.__frame = QFrame(self)self.__frameLayout = QVBoxLayout(self.__frame)self.__layout.addWidget(self.__frame)# 创建编辑器self.__editor = MeQsciScintilla(self.__frame)# 这里设置自定义词法解析器CPPself.__lexer = MeLexer(self.__editor)# 配置MeLexer 里面有自定义的高亮风格self.__editor.setLexer(self.__lexer)# 设置自动补全敏感字数self.__editor.setAutoCompletionThreshold(1)self.__editor.setAutoCompletionSource(QsciScintilla.AcsAll)# 设置自动补全对象self.__api = QsciAPIs(self.__lexer)# 设置自动补全敏感self.__editor.setAutoCompletionCaseSensitivity(True)# 设置自动补全替换self.__editor.setAutoCompletionReplaceWord(True)# 设置自动填充self.__editor.setAutoCompletionFillupsEnabled(True)# 显示全部调用 不受上下文限制self.__editor.setCallTipsStyle(QsciScintilla.CallTipsNoContext)# 自动补全选项在下面self.__editor.setCallTipsPosition(QsciScintilla.CallTipsBelowText)self.__editor.setCallTipsVisible(0)# 菜单# 设置默认菜单为自定义菜单self.__editor.setContextMenuPolicy(Qt.CustomContextMenu)# 设置触发self.__editor.customContextMenuRequested.connect(self.show_context_menu)autocompletions = ['include', 'using', 'namespace', 'std','scanf', 'printf', 'return', 'char', '{}','[]', '()', 'int', 'double', 'long', 'float','string', 'endl', 'stdio.h', 'stdlib.h', 'iostream', '<>','free', 'malloc', 'new', 'delete', 'public', 'private', 'protected','cin', 'cout', 'for', 'while', 'do', 'const', 'continue', 'break', 'if', 'else','auto', 'signed', 'short', 'case', 'try', 'catch', 'switch', 'default','true', 'false', 'struct', 'typedef', 'goto', 'sizeof', 'void', 'static', 'union','enum', 'inline', 'extern', 'throw', 'bool', 'class', 'template', 'this', 'vector','math.h', 'abs', 'strcat', 'strcmp', 'strlen', 'strcpy', 'strchr', 'strstr', 'rand','exit', 'time.h', 'string.h', 'ctype.h', 'isdigit', 'isalpha', 'isblank', 'isalnum','getchar', 'fopen', 'fflush', 'fclose', 'remove', 'fprintf', 'puts', 'abort', 'ctime']for ac in autocompletions:self.__api.add(ac)self.__api.prepare()self.__editor.setCallTipsBackgroundColor(QColor('#D8BFD8'))# 设置自动补全字体颜色self.__editor.setCallTipsForegroundColor(QColor('#F08080'))# utf-8self.__editor.setUtf8(True)# 将编辑器添加到布局中self.__frameLayout.addWidget(self.__editor)# 细节# 设置背景色self.__editor.setPaper(QColor("#CCE8CF"))# 显示自动换行self.__editor.setWrapMode(QsciScintilla.WrapWord)self.__editor.setWrapVisualFlags(QsciScintilla.WrapFlagByText)self.__editor.setWrapIndentMode(QsciScintilla.WrapIndentIndented)# 使用tabself.__editor.setIndentationsUseTabs(True)# 设置换行符长度4self.__editor.setTabWidth(4)# 设置Tab自动对齐self.__editor.setAutoIndent(True)# 设置鼠标光标颜色 前景色...self.__editor.setCaretForegroundColor(QColor("#0000CD"))# 设置选中行颜色self.__editor.setCaretLineVisible(True)self.__editor.setCaretLineBackgroundColor(QColor("#AAEDCB"))# 行号/页边距颜色# 显示行号 行号范围self.__editor.setMarginLineNumbers(1, True)self.__editor.setMarginWidth(1, '0000')self.__editor.setMarginsForegroundColor(QColor("#006400"))# 默认未修改self.__editor.setModified(False)def show_context_menu(self, point):self.context_menu = self.__editor.createStandardContextMenu()# 添加默认选项self.context_menu.insertSeparator(self.context_menu.actions()[0])ui_icon = self.config_ini['main_project']['project_name'] + self.config_ini['ui_img']['ui_turn_to']action_goto_declaration = QAction("转到声明", self)action_goto_declaration.setIcon(QIcon(ui_icon))action_goto_declaration.triggered.connect(self.gotoDeclaration)action_goto_definition = QAction("转到定义", self)action_goto_definition.setIcon(QIcon(ui_icon))action_goto_definition.triggered.connect(self.gotoDefinition)action_goto_call_express = QAction("转到调用", self)action_goto_call_express.setIcon(QIcon(ui_icon))action_goto_call_express.triggered.connect(self.gotoCallExpress)# 分隔符self.context_menu.insertSeparator(self.context_menu.actions()[0])self.context_menu.insertAction(self.context_menu.actions()[0], action_goto_declaration)self.context_menu.insertAction(self.context_menu.actions()[1], action_goto_definition)self.context_menu.insertAction(self.context_menu.actions()[2], action_goto_call_express)# 应用self.context_menu.exec_(self.__editor.mapToGlobal(point))def gotoDeclaration(self):self.gotoDeclarationSign.emit()def gotoDefinition(self):self.gotoDefinitionSign.emit()def gotoCallExpress(self):self.gotoCallExpressSign.emit()def highlight_function_declaration(self, positions):# 传入的是整个位置数据....indicator_number = 1  # 指示器的编号lines = self.__editor.lines() - 1indexs = self.__editor.lineLength(lines)indicator_color = QColor('#f05b72')  # 蔷薇色if positions:self.highlight_handle(positions, lines, indexs, indicator_number, indicator_color)def highlight_function_definition(self, positions):# 传入的是整个位置数据....indicator_number = 2  # 指示器的编号lines = self.__editor.lines() - 1indexs = self.__editor.lineLength(lines)indicator_color = QColor('#ed1941')  # 赤色if positions:self.highlight_handle(positions, lines, indexs, indicator_number, indicator_color)def highlight_function_call_express(self, positions):# 传入的是整个位置数据....indicator_number = 3  # 指示器的编号lines = self.__editor.lines() - 1indexs = self.__editor.lineLength(lines)indicator_color = QColor('#f47920')  # 橙色if positions:self.highlight_handle(positions, lines, indexs, indicator_number, indicator_color)def highlight_handle(self, positions, lines, indexs, indicator_number, indicator_color):self.__editor.SendScintilla(QsciScintilla.SCI_SETINDICATORCURRENT, indicator_number)# 清除所有指示器的色块填充for i in range(1, 4):self.__editor.clearIndicatorRange(0, 0, lines, indexs, i)self.__editor.SendScintilla(QsciScintilla.SCI_INDICATORCLEARRANGE, 0,self.__editor.SendScintilla(QsciScintilla.SCI_GETLINECOUNT))for start_line, start_index, end_line, end_index in positions:self.__editor.SendScintilla(QsciScintilla.SCI_INDICSETSTYLE, indicator_number,QsciScintilla.INDIC_CONTAINER)self.__editor.SendScintilla(QsciScintilla.SCI_INDICSETFORE, indicator_number,indicator_color)self.__editor.fillIndicatorRange(start_line, start_index, end_line, end_index, indicator_number)self.__editor.setCursorPosition(end_line, end_index)# 获取选中位置文本 返回位置和一模一样文本def getSelected_Position_Content(self):if self.__editor.getSelection() != (-1, -1, -1, -1):selected_text = self.__editor.selectedText()start_line = self.__editor.SendScintilla(Qsci.QsciScintilla.SCI_LINEFROMPOSITION,self.__editor.SendScintilla(Qsci.QsciScintilla.SCI_GETSELECTIONSTART))  # 设置起始行号为当前选中文本所在行start_index = self.__editor.SendScintilla(Qsci.QsciScintilla.SCI_GETCOLUMN, self.__editor.SendScintilla(Qsci.QsciScintilla.SCI_GETSELECTIONSTART))  # 设置起始索引为当前选中文本的起始位置end_line = self.__editor.SendScintilla(Qsci.QsciScintilla.SCI_LINEFROMPOSITION, self.__editor.SendScintilla(Qsci.QsciScintilla.SCI_GETSELECTIONEND))  # 设置结束行号为当前选中文本的结束行end_index = self.__editor.SendScintilla(Qsci.QsciScintilla.SCI_GETCOLUMN, self.__editor.SendScintilla(Qsci.QsciScintilla.SCI_GETSELECTIONEND))  # 设置结束索引为当前选中文本的结束位置return [(start_line, start_index, end_line, end_index)], selected_textdef getSelectdFunctionName(self, input_string):import repattern = r'\b(\w+)\s*\('match = re.search(pattern, input_string)if match:return match.group(1)words = re.findall(r'\b\w+\b', input_string)  # 提取字符串中的单词列表for word in words:if re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', word):  # 判断单词是否符合函数名的命名规则return word  # 返回第一个符合要求的单词作为函数名return None# 这里是添加内容def addText(self, content):# 防止有憨憨放列表进来...input_content = ''if isinstance(content, list):if '\r' or '\n' in content:input_content = ''.join(content)else:input_content = '\n'.join(content)elif isinstance(content, str):input_content = contentself.__editor.setText(input_content)# 得到当前文本def getText(self):content = self.__editor.text()content = content.replace('\r', '')return content# 得到编辑器当前状态def getStatus(self):# boolstatus = self.__editor.isModified()return status# 修改当前编辑器状态def changeStatus(self, flag):self.__editor.setModified(flag)# 得到搜索结果....def search_interface(self, keyword, *state):"""obj = QsciScintilla()flag = obj.findFirst(self,expr,re,cs,wo,wrap,forward,line,index,show,posix,cxx11)->bool:param keyword: 你的关键词:param state: 元组(***)tips -> [虽然是 Any 但默认写 bool]expr: Any, --> 匹配词 keywordre: Any, --> 是否使用正则表达式匹配 -> 默认向后搜索 regexpcs: Any, --> 是否区分大小写匹配wo: Any, --> 是否匹配整个关键词 --> 不需要完整匹配 --> Falsewrap: Any, --> 是否在匹配结束之后回到搜索起点 --> 默认是 Trueforward: bool, --> 向前搜索: False, 向后搜索: True; 一般是True即向后搜索... 这里注意不要搞反line: -1, --> 搜索的起始行号 表示从当前行开始... 0~Nindex: -1, --> 搜索的起始索引 表示从当前行的当前光标开始 0~Nshow: True, --> 是否显示搜索结果 默认高亮...显示posix: False, --> 是否使用POSIX正则表达式匹配 默认Falseusername: False, --> 是否用用户名模式匹配 我的用户名: cxx11:return: bool --> 返回一个布尔值 表明是否找到..."""return self.__editor.findFirst(keyword, *state)  # booldef search_interface_(self):# 直接找下一个....return self.__editor.findNext()def send_signal(self, parameter1, parameter2=None):v1 = getattr(self.__editor, parameter1)if parameter2 is None:return self.__editor.SendScintilla(v1)else:return self.__editor.SendScintilla(v1, parameter2)def send_signal_(self, item1, item2):item3 = self.__editor.SendScintilla(item2)return self.__editor.SendScintilla(item1, item3)# 必须搭配findFirst()/findNext()食用 在目标被选中的前提下替换def replace_interface(self, keywords):self.__editor.replace(keywords)def moveCursor(self, line, index):self.__editor.setCursorPosition(line, index)def highlight_text(self, positions):start_line, start_index, end_line, end_index = positionsself.__editor.setSelectionBackgroundColor(QColor('#4169E1'))  # 蓝self.__editor.setSelectionForegroundColor(QColor('#FF8C00'))  # 橘self.__editor.setSelection(start_line, start_index, end_line, end_index)def multi_highlight_text(self, positions):indicator_number = 1  # 指示器的编号lines = self.__editor.lines() - 1indexs = self.__editor.lineLength(lines)self.__editor.SendScintilla(QsciScintilla.SCI_SETINDICATORCURRENT, indicator_number)self.__editor.clearIndicatorRange(0, 0, lines, indexs, indicator_number)for start_line, start_index, end_line, end_index in positions:self.__editor.SendScintilla(QsciScintilla.SCI_INDICSETSTYLE, indicator_number,QsciScintilla.INDIC_CONTAINER)self.__editor.SendScintilla(QsciScintilla.SCI_INDICSETFORE, indicator_number,QColor('#4169E1'))self.__editor.fillIndicatorRange(start_line, start_index, end_line, end_index, indicator_number)def clear_all_indicator_sign(self):indicator_number = 1  # 指示器的编号lines = self.__editor.lines() - 1indexs = self.__editor.lineLength(lines)self.__editor.clearIndicatorRange(0, 0, lines, indexs, indicator_number)def getSelectionState(self):return self.__editor.getSelection()def getCursorLocation(self):return self.__editor.getCursorPosition()
  1. QtabWidget里使用TextEditorWidget
def openfile(self):test_path = self.config_ini["main_project"]["project_name"] + self.config_ini["test"]["folder_path"]fileName, isOk = QFileDialog.getOpenFileName(self, "选取文件", test_path, "C/C++源文件 (*.c *.cpp)")path = ''name = ''if fileName:flag = self.main_detector(fileName)else:message_ = CustomMessageBox(icon=QIcon(self.ui_icon),title='提示',text='您没有选择文件!')message_.exec_()returnif flag:if isOk:path, name = split(fileName)if path:text_editor_obj = TextEditorWidget(filename=name, filepath=path)text_editor_obj.addText(content=content)self.ui.text_editor.addTab(text_editor_obj, text_editor_obj.filename)self.ui.text_editor.setCurrentWidget(text_editor_obj)

查找替换

因为那个重写的QsciScintilla类里有自带的查找findFirst、替换函数replace,但是它并没有说明书,所以又遇到对手了。接下来就需要我们学会自己克服困难,比如说把参数爬下来,丢给大爹让它分析,然后我再自己写一些特殊逻辑。

提前说明:

  1. findFirst
    这个函数有多个参数,传入的方式除了关键词之外,都是bool值,我分析得到的结果如下:
def search_interface(self, keyword, *state):"""obj = QsciScintilla()flag = obj.findFirst(self,expr,re,cs,wo,wrap,forward,line,index,show,posix,cxx11)->bool:param keyword: 你的关键词:param state: 元组(***)tips -> [虽然是 Any 但默认写 bool]expr: Any, --> 匹配词 keywordre: Any, --> 是否使用正则表达式匹配 -> 默认向后搜索 regexpcs: Any, --> 是否区分大小写匹配wo: Any, --> 是否匹配整个关键词 --> 不需要完整匹配 --> Falsewrap: Any, --> 是否在匹配结束之后回到搜索起点 --> 默认是 Trueforward: bool, --> 向前搜索: False, 向后搜索: True; 一般是True即向后搜索... 这里注意不要搞反line: -1, --> 搜索的起始行号 表示从当前行开始... 0~Nindex: -1, --> 搜索的起始索引 表示从当前行的当前光标开始 0~Nshow: True, --> 是否显示搜索结果 默认高亮...显示posix: False, --> 是否使用POSIX正则表达式匹配 默认Falseusername: False, --> 是否用用户名模式匹配 我的用户名: cxx11:return: bool --> 返回一个布尔值 表明是否找到..."""return self.__editor.findFirst(keyword, *state)  # bool
  1. replace
    这个是必须在选中的情况下使用,首先用findFirst查找选中关键词,让这些关键词处于选中状态,然后直接用self.__editor.replace(replace_word)就自动替换完成,注意是选中状态有几个替换几个。

参数说明

区分大小写:就是根据大小写来匹配,如果输入一个全部大写的是不会匹配到小写内容的。
全部匹配:就是必须严格是那个关键词,res只能匹配res不能匹配res1
正则表达式匹配: 根据你输入的关键词得到那个关键词的正则表达式,根据它再查找匹配其他字符。
是否回到搜索起点:默认搜索起点是光标停留处,若不回到就不会循环查找/替换光标范围之外的。
向前/先后搜索:相对于光标停留位置向前或者向后,True是向后
搜索行号:默认-1 默认从第一行,可以自定义,0~N-1
搜索下标:默认-1 默认第一行第一个开始,可以自定义,0~N-1
默认返回值是bool,代表在特定位置上是否找到

范围书写

这里由于替换很简单,只写搜索
替换就是在搜索基础上替换
全部搜索:

def search_all_string(self):self.select_keywords_pos.clear()self.keywords_pos.clear()# 获取输入input_string = self.ui.input_s.currentText()# 判断重复和大小写current_tab = self.father.currentWidget()if input_string and current_tab:# 太棒了! 我逐渐理解一切。# 清空矛盾self.select_keywords_pos.clear()self.keywords_pos.clear()# 关键词positions = set()  # 存储匹配的位置line = 0  # 设置起始行号为0index = 0  # 设置起始索引为0count = 0  # 匹配次数计数器forward = self.isfoward()while True:state = (self.ui.re_s.isChecked(),  # regexpself.ui.cs_s.isChecked(),  # csself.ui.wo_s.isChecked(),  # woFalse,  # 回到开始?forward,  # 向前向后?line,  # 行index,  # 下标True, False, False)flag = current_tab.search_interface(input_string, *state)if not flag:breakfound_pos = current_tab.send_signal(parameter1='SCI_GETCURRENTPOS', parameter2=None)found_line = current_tab.send_signal(parameter1='SCI_LINEFROMPOSITION', parameter2=found_pos)found_index = found_pos - current_tab.send_signal(parameter1='SCI_POSITIONFROMLINE',parameter2=found_line) - 1if len(input_string) > 1:positions.add((found_line, found_index - len(input_string) + 1, found_line,found_index + 1))  # 记录匹配的位置(行号和索引)else:positions.add((found_line, found_index, found_line, found_index + len(input_string)))  # 记录匹配的位置(行号和索引)count += 1line = found_lineindex = found_index + len(input_string)self.keywords_pos = list(positions)current_tab.multi_highlight_text(self.keywords_pos)# self.ui.msg1 && self.ui.msg2self.ui.msg1.setText(f"共搜索到关键词: '{input_string}'  {count}次!")

选中搜索

def search_select_string(self):# 点击之前先清空一切阻碍self.select_keywords_pos.clear()self.keywords_pos.clear()# 获取输入input_string = self.ui.input_s.currentText()current_tab = self.father.currentWidget()if current_tab.getSelectionState() == (-1, -1, -1, -1):message_box = CustomMessageBox(icon=QIcon(self.ui_icon), title='提示', text='请先选中一个区域!')message_box.exec_()elif input_string and current_tab.getSelectionState() != (-1, -1, -1, -1):start_line = current_tab.send_signal_(Qsci.QsciScintilla.SCI_LINEFROMPOSITION,Qsci.QsciScintilla.SCI_GETSELECTIONSTART)start_index = current_tab.send_signal_(Qsci.QsciScintilla.SCI_GETCOLUMN,Qsci.QsciScintilla.SCI_GETSELECTIONSTART)end_line = current_tab.send_signal_(Qsci.QsciScintilla.SCI_LINEFROMPOSITION,Qsci.QsciScintilla.SCI_GETSELECTIONEND)end_index = current_tab.send_signal_(Qsci.QsciScintilla.SCI_GETCOLUMN,Qsci.QsciScintilla.SCI_GETSELECTIONEND)# 存储匹配的位置positions = set()count = 0current_line = start_linecurrent_index = start_indexwhile True:if current_line > end_line:breakstate = (self.ui.re_s.isChecked(),  # regexpself.ui.cs_s.isChecked(),  # csself.ui.wo_s.isChecked(),  # woFalse,  # 回到开始?self.isfoward(),  # 向前向后?current_line,  # 行current_index,  # 下标True, False, False)if (current_index >= end_index and current_line == end_line) or (current_line > end_line):breakflag = current_tab.search_interface(input_string, *state)if flag:found_pos = current_tab.send_signal(parameter1='SCI_GETCURRENTPOS', parameter2=None)found_line = current_tab.send_signal(parameter1='SCI_LINEFROMPOSITION', parameter2=found_pos)found_index = found_pos - current_tab.send_signal(parameter1='SCI_POSITIONFROMLINE',parameter2=found_line) - 1current_line = found_linecurrent_index = found_index + len(input_string)# 再判断 因为这个先加if current_line > end_line:breakif len(input_string) > 1:positions.add((found_line, found_index - len(input_string) + 1, found_line,found_index + 1))  # 记录匹配的位置(行号和索引)else:positions.add((found_line, found_index, found_line, found_index + len(input_string)))  # 记录匹配的位置(行号和索引)count += 1else:# 搜不到就需要换行....if current_index <= end_index and current_line <= end_line:current_index += len(input_string)elif current_line <= end_line and current_index > end_index:current_index = 0current_line += 1self.select_keywords_pos = list(positions)current_tab.multi_highlight_text(self.select_keywords_pos)self.ui.msg1.setText(f"共搜索到关键词: '{input_string}'  {count}次!")

干货干得要缺水了!
语法树到时候更是重量级…

任重而道远…
放在另一篇里面吧…
这里是链接
不知不觉竟然写了这么多代码(嗐)
如果付出和收获对等,我也能成为最强吗?

[手搓人]大战[高亮编辑器/查找替换/函数跳跳蛙]--巅峰对决(1)相关推荐

  1. [手搓人]大战[高亮编辑器/查找替换/函数跳跳蛙]--巅峰对决(2)

    前置知识 抽象语法树 基本介绍 AST(Abstract Syntax Tree)抽象语法树,当你有一段源代码的时候,是用于表示该源代码的抽象语法结构的树状图.对于不同的语言,有不同的抽象语法树结构, ...

  2. ubuntu中查找文件后高亮_vim查找替换及取消高亮

    查找替换的格式如下: :[range]s[ubstitute]/{pattern}/{string}/[flags] [count] range可以是 .  点号表示在当前行查找(这是默认的range ...

  3. PostgreSQL 查找替换函数

    介绍 PostgreSQL 替换函数,这些函数在字符串中搜索子字符串并将其替换为新的子字符串. PostgreSQL REPLACE 函数 有时,您想搜索列中的字符串并将其替换为新字符串,例如替换过时 ...

  4. Excel字符函数(5):REPLACE、SUBSTITUTE查找替换函数之区别

    文本字符串中用 new_text 替换 old_text. 如果需要在某一文本字符串中替换指定的文本,使用函数 SUBSTITUTE: 如果需要在某一文本字符串中替换特定位置处的任意文本,使用函数 R ...

  5. html编辑器查找与替换,织梦kindeditor文本编辑器增加“查找替换”功能

    织梦kindeditor文本编辑器增加"查找替换"功能效果演示 1.items 里面增加 search 按钮 ['source','|','undo','redo','|','pr ...

  6. 找不到 查找_当心Excel查找替换错误,别犯“台风致山东全省人死亡”的错误

    哈喽,大家好!我是爱踢汪.最近让大家最关注的一定是台风利奇马吧,全国人民的心都为此揪在了一起,各大平台也都纷纷关注.近日,腾讯视频可以说闹了个笑话,在对台风的报道中,竟然说台风利奇马已致全省人死亡,这 ...

  7. Vim查找替换操作 --- 查找和替换

    查找替换 查找和替换是编辑器中最常用的功能之一,在普通编辑器当中查找替换时,你可能需要先移动鼠标在菜单中点击查找的功能,输入查找内容,再点击确认查找.而在vim中,所有的操作只需要敲击几下键盘就行了, ...

  8. 狂肝10个月手搓GPU,他们在《我的世界》里面玩《我的世界》

    梦晨 衡宇 萧箫 发自 凹非寺 量子位 | 公众号 QbitAI 自从有人在<我的世界>里用红石电路造出CPU,就流传着一个梗: 总有一天,这帮红石佬能在我的世界里玩上我的世界. 这一天, ...

  9. 手柄映射键盘_“吃鸡”直接匹配“手搓”玩家?北通G2是一款非常好用的手柄...

    大家好,欢迎来到<刺激实战教室>,我是你们的老朋友刺激哥. 作为一名吃鸡手游的爱好者,刺激哥的水平虽然并不见得有多好,但入手的游戏手柄可是真的一点都不少. 前前后后,接连入手了数款手机手柄 ...

最新文章

  1. Ajax实现在textbox中输入内容,动态从数据库中模糊查询显示到下拉框中
  2. Python str类型方法实例概述及常用方法——04
  3. python父类和子类_python子类父类
  4. Siamese-RPN目标跟踪算法
  5. Java中Volatile关键字详解
  6. 在Linux下安装配置phpMyAdmin步骤
  7. JavaScript发布订阅者模式
  8. SpringBoot整合Mybatis-Plus分页失效,Mybatis-Plus 3.4.1分页插件失效踩坑
  9. Open Source Blog 开源ASP.NET/C# 博客平台 v2.5 发布(提供源码下载)
  10. python矩阵中插入矩阵_Python | 矩阵的痕迹
  11. 墨天轮社区专属福利:与作者互动问答,民工哥全新力作《Linux系统运维指南:从入门到企业实战》送上!...
  12. c语言中浮点数如何声明,C语言中浮点数定义和文本处理的配合
  13. ocp认证考试指南第一章
  14. 学习C++项目——mysql 数据库知识学习(关于 mysql 8.0 版以后基础部分学习)
  15. Sql Sever 注册服务器 [SQL Server]
  16. 计算机基础综合知识试题及答案,计算机基础综合知识试题及答案
  17. 安装SQL 2000挂起的解决办法
  18. 6英寸划片机 陆芯3252半自动单轴晶圆切割机
  19. springnbsp;contextnbsp;初始化两次导致dub…
  20. 工作杂谈之说说工作中的二宗罪

热门文章

  1. Pin码重复出现死循环解决之道
  2. C语言 函数调用方式以及嵌套调用
  3. ubuntu下打开pdf文件
  4. 企业级 DevOps 究竟是什么?
  5. 基于51单片机十字路交通灯仿真_黄灯闪烁_正常模式+夜间模式+紧急模式
  6. texstudio 使用方法_如何使用 TeX Live 和 TeXstudio 操作 LaTeX?
  7. 精细化学品化学习题与答案
  8. iconv 转换文件编码
  9. 从月薪3千到年薪40W,流水线女工到测试工程师,她的8年书写了一个女孩的史诗
  10. Python+SQL万字案例:用户行为数据分析实战!