python3+PyQt5实现理解python语法并做⾼亮显⽰的纯⽂本编辑器
本⽂通过Python3+PyQt5实现《python Qt Gui 快速编程》这本书13章程序理解python语法并做⾼亮显⽰的纯⽂本编辑器,采QSyntaxHighlighter类库。
#!/usr/bin/env python3
import os
import sys
from PyQt5.QtCore import (QEvent, QFile, QFileInfo, QIODevice, QRegExp,
QTextStream,Qt)
from PyQt5.QtWidgets import (QAction, QApplication, QFileDialog,
QMainWindow, QMessageBox, QTextEdit)
from PyQt5.QtGui import QFont, QIcon,QColor,QKeySequence,QSyntaxHighlighter,QTextCharFormat,QTextCursor
import qrc_resources
__version__ = "1.1.0"
class PythonHighlighter(QSyntaxHighlighter):
Rules = []
Formats = {}
def__init__(self, parent=None):
super(PythonHighlighter, self).__init__(parent)
svg动态排版self.initializeFormats()
KEYWORDS = ["and", "as", "assert", "break", "class",
"continue", "def", "del", "elif", "else", "except",
"exec", "finally", "for", "from", "global", "if",
"import", "in", "is", "lambda", "not", "or", "pass",
"print", "raise", "return", "try", "while", "with",
"yield"]
BUILTINS = ["abs", "all", "any", "basestring", "bool",
"callable", "chr", "classmethod", "cmp", "compile",
"complex", "delattr", "dict", "dir", "divmod",
"enumerate", "eval", "execfile", "exit", "file",
"filter", "float", "frozenset", "getattr", "globals",
"hasattr", "hex", "id", "int", "isinstance",
"issubclass", "iter", "len", "list", "locals", "map",
"max", "min", "object", "oct", "open", "ord", "pow",
"property", "range", "reduce", "repr", "reversed",
"round", "set", "setattr", "slice", "sorted",
"staticmethod", "str", "sum", "super", "tuple", "type",
"vars", "zip"]
CONSTANTS = ["False", "True", "None", "NotImplemented",
"Ellipsis"]
PythonHighlighter.Rules.append((QRegExp(
"|".join([r"\b%s\b" % keyword for keyword in KEYWORDS])),
"keyword"))
PythonHighlighter.Rules.append((QRegExp(
"|".join([r"\b%s\b" % builtin for builtin in BUILTINS])),
"builtin"))
PythonHighlighter.Rules.append((QRegExp(
"|".join([r"\b%s\b" % constant
for constant in CONSTANTS])), "constant"))
PythonHighlighter.Rules.append((QRegExp(
r"\b[+-]?[0-9]+[lL]?\b"
r"|\b[+-]?0[xX][0-9A-Fa-f]+[lL]?\b"
r"|\b[+-]?[0-9]+(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\b"),
r"|\b[+-]?[0-9]+(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\b"),
"number"))
PythonHighlighter.Rules.append((QRegExp(
r"\bPyQt4\b|\bQt?[A-Z][a-z]\w+\b"), "pyqt"))
PythonHighlighter.Rules.append((QRegExp(r"\b@\w+\b"),
"decorator"))
stringRe = QRegExp(r"""(?:'[^']*'|"[^"]*")""")
stringRe.setMinimal(True)
PythonHighlighter.Rules.append((stringRe, "string"))
self.stringRe = QRegExp(r"""(:?"["]".*"["]"|'''.*''')""")
self.stringRe.setMinimal(True)
PythonHighlighter.Rules.append((self.stringRe, "string"))
@staticmethod
def initializeFormats():
baseFormat = QTextCharFormat()
baseFormat.setFontFamily("courier")
baseFormat.setFontPointSize(12)
for name, color in (("normal", Qt.black),
易语言最新完美版("keyword", Qt.darkBlue), ("builtin", Qt.darkRed),
("constant", Qt.darkGreen),
("decorator", Qt.darkBlue), ("comment", Qt.darkGreen),
("string", Qt.darkYellow), ("number", Qt.darkMagenta),
("error", Qt.darkRed), ("pyqt", Qt.darkCyan)):
format = QTextCharFormat(baseFormat)
format.setForeground(QColor(color))
if name in ("keyword", "decorator"):
format.setFontWeight(QFont.Bold)
if name == "comment":
format.setFontItalic(True)
PythonHighlighter.Formats[name] = format
def highlightBlock(self, text):
NORMAL, TRIPLESINGLE, TRIPLEDOUBLE, ERROR = range(4)
textLength = len(text)
prevState = self.previousBlockState()
self.setFormat(0, textLength,
PythonHighlighter.Formats["normal"])
if text.startswith("Traceback") or text.startswith("Error: "):
self.setCurrentBlockState(ERROR)
self.setFormat(0, textLength,
PythonHighlighter.Formats["error"])
return
if (prevState == ERROR and
not (text.startswith(sys.ps1) or text.startswith("#"))):
self.setCurrentBlockState(ERROR)
self.setFormat(0, textLength,
PythonHighlighter.Formats["error"])could not transfer artifact
return
for regex, format in PythonHighlighter.Rules:
i = regex.indexIn(text)
while i >= 0:
length = regex.matchedLength()
self.setFormat(i, length,
PythonHighlighter.Formats[format])
i = regex.indexIn(text, i + length)
# Slow but good quality highlighting for comments. For more
# Slow but good quality highlighting for comments. For more
# speed, comment this out and add the following to __init__:
# PythonHighlighter.Rules.append((QRegExp(r"#.*"), "comment")) if not text:
pass
elif text[0] == "#":
self.setFormat(0, len(text),
PythonHighlighter.Formats["comment"])
else:
stack = []
for i, c in enumerate(text):
if c in ('"', "'"):
if stack and stack[-1] == c:
stack.pop()
else:
stack.append(c)
elif c == "#"and len(stack) == 0:
self.setFormat(i, len(text),
PythonHighlighter.Formats["comment"])
break
self.setCurrentBlockState(NORMAL)
if self.stringRe.indexIn(text) != -1:
return
# This is fooled by triple quotes inside single quoted strings
for i, state in ((ipleSingleRe.indexIn(text),
TRIPLESINGLE),
(ipleDoubleRe.indexIn(text),
TRIPLEDOUBLE)):
if self.previousBlockState() == state:
if i == -1:
i = text.length()
self.setCurrentBlockState(state)
self.setFormat(0, i + 3,
PythonHighlighter.Formats["string"])
elif i > -1:
self.setCurrentBlockState(state)
self.setFormat(i, text.length(),
PythonHighlighter.Formats["string"])
def rehighlight(self):
QApplication.setOverrideCursor(QCursor(
Qt.WaitCursor))
class TextEdit(QTextEdit):
def__init__(self, parent=None):
super(TextEdit, self).__init__(parent)
def event(self, event):
if (pe() == QEvent.KeyPress and
event.key() == Qt.Key_Tab):
cursor = Cursor()
cursor.insertText(" ")
return True
return QTextEdit.event(self, event)
class MainWindow(QMainWindow):
def__init__(self, filename=None, parent=None):
super(MainWindow, self).__init__(parent)
font = QFont("Courier", 11)
font.setFixedPitch(True)
self.editor = TextEdit()
self.editor.setFont(font)
self.highlighter = PythonHighlighter(self.editor.document())
self.setCentralWidget(self.editor)
status = self.statusBar()
status.setSizeGripEnabled(False)
status.showMessage("Ready", 5000)
fileNewAction = ateAction("&", self.fileNew,
QKeySequence.New, "filenew", "Create a Python file")
fileOpenAction = ateAction("&", self.fileOpen,
QKeySequence.Open, "fileopen",
"Open an existing Python file")
self.fileSaveAction = ateAction("&Save", self.fileSave,
QKeySequence.Save, "filesave", "Save the file")
self.fileSaveAsAction = ateAction("Save &",
self.fileSaveAs, icon="filesaveas",
tip="Save the file using a new name")
fileQuitAction = ateAction("&Quit", self.close,
"Ctrl+Q", "filequit", "Close the application")
self.editCopyAction = ateAction("&Copy",
py, QKeySequence.Copy, "editcopy",
"Copy text to the clipboard")
self.editCutAction = ateAction("Cu&t", self.editor.cut,
QKeySequence.Cut, "editcut",
"Cut text to the clipboard")
self.editPasteAction = ateAction("&Paste",
self.editor.paste, QKeySequence.Paste, "editpaste",
"Paste in the clipboard's text")
self.editIndentAction = ateAction("&Indent",
self.editIndent, "Ctrl+]", "editindent",
"Indent the current line or selection")
self.editUnindentAction = ateAction("&Unindent",
self.editUnindent, "Ctrl+[", "editunindent",
"Unindent the current line or selection")
fileMenu = uBar().addMenu("&File")
self.addActions(fileMenu, (fileNewAction, fileOpenAction,
self.fileSaveAction, self.fileSaveAsAction, None,
fileQuitAction))
editMenu = uBar().addMenu("&Edit")
self.addActions(editMenu, (self.editCopyAction,
self.editCutAction, self.editPasteAction, None,
self.editIndentAction, self.editUnindentAction))
fileToolbar = self.addToolBar("File")
fileToolbar.setObjectName("FileToolBar")
self.addActions(fileToolbar, (fileNewAction, fileOpenAction,
self.fileSaveAction))
editToolbar = self.addToolBar("Edit")
editToolbar.setObjectName("EditToolBar")
self.addActions(editToolbar, (self.editCopyAction,
self.editCutAction, self.editPasteAction, None,
self.editIndentAction, self.editUnindentAction))
self.t(self.updateUi)
self.editor.document().t(self.updateUi) QApplication.clipboard().t(self.updateUi)
self.setWindowTitle("Python Editor")
self.filename = filename
if self.filename is not None:
self.loadFile()
self.updateUi()
def updateUi(self, arg=None):
self.fileSaveAction.setEnabled(
self.editor.document().isModified())
enable = not self.editor.document().isEmpty()
self.fileSaveAsAction.setEnabled(enable)
self.editIndentAction.setEnabled(enable)
self.editUnindentAction.setEnabled(enable)
enable = Cursor().hasSelection()
self.editCopyAction.setEnabled(enable)
self.editCutAction.setEnabled(enable)
self.editPasteAction.setEnabled(self.editor.canPaste())
def createAction(self, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False, signal="triggered()"):
action = QAction(text, self)
if icon is not None:
action.setIcon(QIcon(":/{0}.png".format(icon)))
if shortcut is not None:
action.setShortcut(shortcut)
python入门教程编辑器if tip is not None:logistical
action.setToolTip(tip)
action.setStatusTip(tip)
if slot is not None:
if checkable:
action.setCheckable(True)
return action
def addActions(self, target, actions):
for action in actions:
if action is None:
target.addSeparator()
else:
target.addAction(action)
def closeEvent(self, event):
if not self.okToContinue():
event.ignore()
def okToContinue(self):
if self.editor.document().isModified():
reply = QMessageBox.question(self,
"Python Editor - Unsaved Changes",
"Save unsaved changes?",
QMessageBox.Yes|QMessageBox.No|
stand upQMessageBox.Cancel)
if reply == QMessageBox.Cancel:
return False
elif reply == QMessageBox.Yes:
return self.fileSave()
return True
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论