一个简单的文本编辑器
features:
1.open 一个文件夹作为项目
2.save 保存当前窗口的内容
3.退出
4.双击文件可以打开文件内容
5.简单的python高亮
6.双击相同文件,会找到之前打开过的文件
打开一个文件夹
打开项目,双击打开文件
保存
代码:
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import *
from PyQt6.QtCore import *
from PyQt6.QtGui import *
import sys
import os
from highlight import *
class FileSystemModel(QFileSystemModel):
def __init__(self, headName, parent=None):
super().__init__(parent)
self.headName = headName
'''
只显示名称,不显示类型和其他的信息
'''
def columnCount(self, parent=QModelIndex()):
return 1
#修改表头的列名
def headerData(self, section: int, orientation: Qt.Orientation, role: int = ...):
if orientation == Qt.Orientation.Horizontal and role == Qt.ItemDataRole.DisplayRole:
return self.headName
return super().headerData(section, orientation, role)
class TextEditor(QMainWindow):
def __init__(self):
super().__init__()
self._initUI()
self._initConnect()
def _initUI(self):
self.setWindowTitle('Text Editor')
self.resize(800, 600)
centerWidget = QWidget()
mainLayout = QHBoxLayout()
self.left_file_tree = QTreeView()
self.right_editor = QTabWidget()
self.right_editor.setDocumentMode(True)
self.right_editor.setTabsClosable(True)
mainLayout.addWidget(self.left_file_tree)
mainLayout.addWidget(self.right_editor)
mainLayout.setSpacing(0)
mainLayout.setContentsMargins(0, 0, 0, 0)
mainLayout.setStretchFactor(self.left_file_tree, 1)
mainLayout.setStretchFactor(self.right_editor, 4)
centerWidget.setLayout(mainLayout)
self.setCentralWidget(centerWidget)
self._init_menu()
def _init_menu(self):
menubar = self.menuBar()
menubar.setNativeMenuBar(False)
fileMenu = menubar.addMenu('File')
fileMenu.addAction('Open', self._open_folder)
fileMenu.addAction('Save', self.save)
fileMenu.addAction('Exit', self.close)
def save(self):
currentWidget = self.right_editor.currentWidget()
if currentWidget:
file_name = currentWidget.objectName()
with open(file_name, 'w') as f:
text = currentWidget.toPlainText()
f.write(text)
def _open_folder(self):
dir = QFileDialog.getExistingDirectory(self, 'Open Folder', './')
self.dir_path = dir
self._init_file_tree(dir)
self.right_editor.clear()
def _init_file_tree(self, dir_path):
dirname = os.path.basename(dir_path)
self.model = FileSystemModel(dirname)
self.model.setRootPath(dir_path)
self.left_file_tree.setModel(self.model)
#这里需要强制指定,否则显示root目录
self.left_file_tree.setRootIndex(self.model.index(dir_path))
def _initConnect(self):
self.left_file_tree.doubleClicked.connect(self.on_file_tree_clicked)
self.right_editor.tabCloseRequested.connect(self.close_current_tab)
def close_current_tab(self, index):
self.right_editor.removeTab(index)
def on_file_tree_clicked(self, index):
isDir = self.model.isDir(index)
if not isDir:
file_path = self.model.filePath(index)
file_name = self.model.data(index)
for i in range(self.right_editor.count()):
tab = self.right_editor.widget(i)
if tab.objectName() == file_path:
self.right_editor.setCurrentIndex(i)
return
fileEditor = QTextEdit()
highlighter = SqlHighlighter(fileEditor.document())
fileEditor.setObjectName(file_path)
with open(file_path, 'r', encoding='utf-8') as f:
fileEditor.setText(f.read())
self.right_editor.addTab(fileEditor, file_name)
self.right_editor.setCurrentIndex(self.right_editor.count()-1)
def close(self):
self.close()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = TextEditor()
window.show()
sys.exit(app.exec())
from PyQt6.QtWidgets import *
from PyQt6.QtGui import *
from PyQt6.QtCore import *
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.Weight.Bold)
if 'italic' in style:
_format.setFontItalic(True)
return _format
STYLES = {
'keyword': format([50, 50, 150], 'bold'),
'operator': format([150, 150, 150]),
'brace': format('darkGray'),
'defclass': format([220, 220, 255], 'bold'),
'string': format([20, 110, 100]),
'string2': format([30, 120, 110]),
'comment': format([128, 128, 128]),
'self': format([150, 85, 140], 'italic'),
'numbers': format([100, 150, 190]),
}
class SqlHighlighter(QSyntaxHighlighter):
keywords = [
'def', 'return', 'for', 'in', 'while', 'if', 'elif', 'else',
'None', 'True', 'False', 'and', 'or', 'not', 'as', 'break',
'super', 'self', 'del', 'except', 'finally', 'is', 'class',
'lambda', 'try', 'with', 'from', 'nonlocal', 'pass', 'raise',
'assert', 'return', 'break', 'import', 'return', 'break', 'continue',
'yield', 'global',
]
braces = [
'\{', '\}', '\(', '\)', '\[', '\]',
]
def __init__(self, document):
super().__init__(document)
rules = []
# Keyword, operator, and brace rules
rules += [(r'\b%s\b' % w, 0, STYLES['keyword'])
for w in SqlHighlighter.keywords]
rules += [(r'%s' % b, 0, STYLES['brace'])
for b in SqlHighlighter.braces]
self.rules = [(QRegularExpression(pat), index, fmt) for (pat, index, fmt) in rules]
def highlightBlock(self, text: str) -> None:
"""Apply syntax highlighting to the given block of text.
"""
# Do other syntax formatting
for expression, nth, format in self.rules:
matchIterator = expression.globalMatch(text)
while matchIterator.hasNext():
# print(rule.pattern.pattern())
match = matchIterator.next()
self.setFormat(match.capturedStart(), match.capturedLength(), format)
self.setCurrentBlockState(0)
代码地址:
GitHub - chunlaiqingke/Tiny-Tool
公众号