Создаем текстовый редактор с помощью Python и библиотек GUI
Разработка собственного текстового редактора позволяет лучше понять принципы работы GUI приложений и адаптировать инструмент под конкретные задачи. В этой части рассмотрены несколько подходов с использованием различных библиотек Python.
Создание текстового редактора на Python
Как создать простой редактор на Tkinter?
Tkinter входит в стандартную поставку Python, поэтому не требует установки. Это оптимальный выбор для быстрого прототипирования. Основные компоненты: окно, текстовое поле, меню.
import tkinter as tk
from tkinter import filedialog, messagebox
def open_file():
file_path = filedialog.askopenfilename()
if file_path:
with open(file_path, 'r', encoding='utf-8') as f:
text.delete('1.0', tk.END)
text.insert(tk.END, f.read())
def save_file():
file_path = filedialog.asksaveasfilename(defaultextension=".txt")
if file_path:
with open(file_path, 'w', encoding='utf-8') as f:
f.write(text.get('1.0', tk.END))
root = tk.Tk()
root.title("Простой редактор")
menu = tk.Menu(root)
root.config(menu=menu)
file_menu = tk.Menu(menu, tearoff=0)
menu.add_cascade(label="Файл", menu=file_menu)
file_menu.add_command(label="Открыть", command=open_file)
file_menu.add_command(label="Сохранить", command=save_file)
file_menu.add_separator()
file_menu.add_command(label="Выход", command=root.quit)
text = tk.Text(root, wrap='word', undo=True)
text.pack(fill=tk.BOTH, expand=True)
root.mainloop()
Python написать редактор (создание редактора на python)
Этот код создаёт окно с текстовым полем и меню. Функции open_file и save_file реализуют диалоги открытия и сохранения. Важно указывать кодировку utf-8 для корректной работы с русским текстом.
Как добавить подсветку синтаксиса в редактор на Tkinter?
Если требуется редактор кода, можно использовать теги Text для раскраски ключевых слов. Ниже приведён пример для подсветки синтаксиса Python.
import tkinter as tk
import re
root = tk.Tk()
text = tk.Text(root)
text.pack(fill=tk.BOTH, expand=True)
def highlight(event=None):
text.tag_remove("keyword", "1.0", tk.END)
keywords = ["def", "class", "if", "else", "for", "while", "import", "from"]
for kw in keywords:
start = "1.0"
while True:
pos = text.search(kw, start, tk.END)
if not pos:
break
end = f"{pos}+{len(kw)}c"
text.tag_add("keyword", pos, end)
start = end
text.tag_config("keyword", foreground="blue", font=("Courier New", 10, "bold"))
text.bind("", highlight)
root.mainloop()
После каждого ввода символа функция highlight ищет ключевые слова и присваивает им тег с синим цветом. Для больших файлов это может замедлить работу, поэтому рекомендуется использовать advanced синтаксические анализаторы.
Как реализовать редактор на PyQt5 с нумерацией строк?
PyQt5 предоставляет мощный виджет QPlainTextEdit, а также QScintilla для подсветки. Для нумерации строк можно subclass QPlainTextEdit.
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QTextEdit, QWidget, QVBoxLayout, QLabel
from PyQt5.QtGui import QPainter, QColor
from PyQt5.QtCore import Qt
class LineNumberArea(QWidget):
def __init__(self, editor):
super().__init__(editor)
self.editor = editor
def paintEvent(self, event):
painter = QPainter(self)
painter.fillRect(event.rect(), QColor(240, 240, 240))
block = self.editor.firstVisibleBlock()
lineNumber = block.blockNumber()
top = self.editor.blockBoundingGeometry(block).translated(self.editor.contentOffset()).top()
while block.isValid() and top <= event.rect().bottom():
if block.isVisible():
number = str(lineNumber + 1)
painter.setPen(Qt.black)
painter.drawText(0, int(top), self.width(), self.editor.fontMetrics().height(), Qt.AlignRight, number)
block = block.next()
top = self.editor.blockBoundingGeometry(block).translated(self.editor.contentOffset()).top()
lineNumber += 1
class CodeEditor(QTextEdit):
def __init__(self):
super().__init__()
self.lineNumberArea = LineNumberArea(self)
self.blockCountChanged.connect(self.updateLineNumberAreaWidth)
self.updateRequest.connect(self.updateLineNumberArea)
self.updateLineNumberAreaWidth()
def resizeEvent(self, event):
super().resizeEvent(event)
cr = self.contentsRect()
self.lineNumberArea.setGeometry(cr.left(), cr.top(), self.lineNumberAreaWidth(), cr.height())
def lineNumberAreaWidth(self):
return 30
def updateLineNumberAreaWidth(self):
self.setViewportMargins(self.lineNumberAreaWidth(), 0, 0, 0)
def updateLineNumberArea(self, rect, dy):
if dy:
self.lineNumberArea.scroll(0, dy)
else:
self.lineNumberArea.update(0, rect.y(), self.lineNumberArea.width(), rect.height())
app = QApplication(sys.argv)
window = QMainWindow()
editor = CodeEditor()
window.setCentralWidget(editor)
window.show()
sys.exit(app.exec_())
Этот код отображает нумерацию строк слева от текста. Для реального редактора стоит добавить меню, открытие/сохранение и подсветку синтаксиса через QScintilla.
Как сделать редактор для мобильных устройств на Kivy?
Kivy ориентирован на кроссплатформенные приложения с сенсорным управлением. Основной виджет TextInput поддерживает многострочный текст.
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.popup import Popup
from kivy.core.window import Window
class EditorApp(App):
def build(self):
layout = BoxLayout(orientation='vertical')
self.text_input = TextInput(font_size=20)
layout.add_widget(self.text_input)
btn_layout = BoxLayout(size_hint_y=0.1)
btn_open = Button(text='Открыть')
btn_save = Button(text='Сохранить')
btn_layout.add_widget(btn_open)
btn_layout.add_widget(btn_save)
layout.add_widget(btn_layout)
return layout
if __name__ == '__main__':
EditorApp().run()
Этот пример создаёт интерфейс с текстовым полем и кнопками. Для открытия/сохранения файлов на мобильных устройствах потребуется использовать Storage API или диалоги Kivy.
Расширенные примеры
Рассмотрим более сложные реализации редакторов с дополнительными возможностями.
Пример 1: Редактор с закладками и поиском на Tkinter
Добавление функционала поиска и замены, а также закладок (bookmarks) для быстрого перехода по файлу.
import tkinter as tk
from tkinter import scrolledtext
class EditorWithSearch:
def __init__(self, root):
self.root = root
self.text = scrolledtext.ScrolledText(root, wrap='word', undo=True)
self.text.pack(fill=tk.BOTH, expand=True)
self.create_menu()
self.search_var = tk.StringVar()
def create_menu(self):
menubar = tk.Menu(self.root)
self.root.config(menu=menubar)
edit_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label="Правка", menu=edit_menu)
edit_menu.add_command(label="Найти", command=self.open_search_dialog)
search_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label="Поиск", menu=search_menu)
def open_search_dialog(self):
dialog = tk.Toplevel(self.root)
dialog.title("Поиск")
tk.Label(dialog, text="Искать:").grid(row=0, column=0)
entry = tk.Entry(dialog, textvariable=self.search_var)
entry.grid(row=0, column=1)
tk.Button(dialog, text="Найти далее", command=self.find_next).grid(row=1, column=0, columnspan=2)
def find_next(self):
self.text.tag_remove("found", "1.0", tk.END)
query = self.search_var.get()
if query:
idx = "1.0"
while True:
idx = self.text.search(query, idx, nocase=1, stopindex=tk.END)
if not idx:
break
end_idx = f"{idx}+{len(query)}c"
self.text.tag_add("found", idx, end_idx)
idx = end_idx
self.text.tag_config("found", background="yellow")
root = tk.Tk()
app = EditorWithSearch(root)
root.mainloop()
Результат: главное окно с текстовым полем, при выборе пункта меню "Найти" открывается диалог, после ввода и нажатия кнопки все найденные совпадения подсвечиваются жёлтым.
Пример 2: Полноценный редактор кода на PyQt5 с QScintilla
QScintilla предоставляет подсветку синтаксиса, автодополнение и нумерацию строк "из коробки". Ниже пример интеграции.
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.Qsci import QsciScintilla, QsciLexerPython
import sys
class CodeEditor(QMainWindow):
def __init__(self):
super().__init__()
self.editor = QsciScintilla()
self.setCentralWidget(self.editor)
lexer = QsciLexerPython()
self.editor.setLexer(lexer)
self.editor.setMarginWidth(0, 30)
self.editor.setMarginLineNumbers(0, True)
self.editor.setFolding(QsciScintilla.BoxedFoldStyle)
self.setWindowTitle("Редактор кода")
app = QApplication(sys.argv)
window = CodeEditor()
window.show()
sys.exit(app.exec_())
Результат: окно с подсветкой синтаксиса Python, номера строк, сворачивание блоков кода. Диалоги открытия/сохранения можно добавить через QFileDialog.