<===
2025-10-02 08:44:15
$ cat notes.py
import sys
import sqlite3
from datetime import datetime
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QLineEdit, QTextEdit, QPushButton, QTableWidget, QTableWidgetItem,
QMessageBox, QHeaderView, QInputDialog)
from PyQt5.QtCore import Qt
class NotebookApp(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Записная книжка")
self.setGeometry(100, 100, 800, 600)
# Инициализация базы данных
self.conn = sqlite3.connect("notebook.db")
self.create_database()
# Основной виджет и компоновка
self.central_widget = QWidget()
self.setCentralWidget(self.central_widget)
self.layout = QVBoxLayout(self.central_widget)
# Поле для ввода заметки
self.note_input = QTextEdit()
self.note_input.setPlaceholderText("Введите заметку (до 255 символов)")
self.note_input.setFixedHeight(100)
self.layout.addWidget(self.note_input)
# Кнопки для добавления и очистки
self.button_layout = QHBoxLayout()
self.add_button = QPushButton("Добавить заметку")
self.add_button.clicked.connect(self.add_note)
self.clear_button = QPushButton("Очистить")
self.clear_button.clicked.connect(self.clear_input)
self.button_layout.addWidget(self.add_button)
self.button_layout.addWidget(self.clear_button)
self.layout.addLayout(self.button_layout)
# Поле для поиска
self.search_input = QLineEdit()
self.search_input.setPlaceholderText("Введите запрос для поиска...")
self.search_input.textChanged.connect(self.search_notes)
self.layout.addWidget(self.search_input)
# Таблица для отображения заметок
self.table = QTableWidget()
self.table.setColumnCount(3)
self.table.setHorizontalHeaderLabels(["ID", "Дата", "Заметка"])
self.table.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch)
self.table.setColumnWidth(0, 50)
self.table.setColumnWidth(1, 150)
self.table.setSelectionBehavior(QTableWidget.SelectRows)
self.table.setEditTriggers(QTableWidget.NoEditTriggers)
self.table.cellDoubleClicked.connect(self.edit_note)
self.layout.addWidget(self.table)
# Кнопки для редактирования и удаления
self.action_layout = QHBoxLayout()
self.edit_button = QPushButton("Редактировать")
self.edit_button.clicked.connect(self.edit_selected_note)
self.delete_button = QPushButton("Удалить")
self.delete_button.clicked.connect(self.delete_note)
self.action_layout.addWidget(self.edit_button)
self.action_layout.addWidget(self.delete_button)
self.layout.addLayout(self.action_layout)
# Загрузка заметок при запуске
self.load_notes()
def create_database(self):
cursor = self.conn.cursor()
# Создание таблицы notes
cursor.execute("""
CREATE TABLE IF NOT EXISTS notes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
date TEXT NOT NULL,
note TEXT NOT NULL
)
""")
# Создание виртуальной таблицы для FTS5
cursor.execute("""
CREATE VIRTUAL TABLE IF NOT EXISTS notes_fts USING fts5(
note,
content='notes',
content_rowid='id'
)
""")
# Создание триггеров для синхронизации FTS5 с таблицей notes
cursor.execute("""
CREATE TRIGGER IF NOT EXISTS notes_insert AFTER INSERT ON notes
BEGIN
INSERT INTO notes_fts(rowid, note) VALUES (new.id, new.note);
END
""")
cursor.execute("""
CREATE TRIGGER IF NOT EXISTS notes_update AFTER UPDATE ON notes
BEGIN
INSERT INTO notes_fts(rowid, note) VALUES (new.id, new.note);
END
""")
cursor.execute("""
CREATE TRIGGER IF NOT EXISTS notes_delete AFTER DELETE ON notes
BEGIN
INSERT INTO notes_fts(notes_fts, rowid, note) VALUES ('delete', old.id, old.note);
END
""")
self.conn.commit()
def add_note(self):
note = self.note_input.toPlainText().strip()
if not note:
QMessageBox.warning(self, "Ошибка", "Заметка не может быть пустой!")
return
if len(note) > 255:
QMessageBox.warning(self, "Ошибка", "Заметка не может превышать 255 символов!")
return
date = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
cursor = self.conn.cursor()
cursor.execute("INSERT INTO notes (date, note) VALUES (?, ?)", (date, note))
self.conn.commit()
self.note_input.clear()
self.load_notes()
def clear_input(self):
self.note_input.clear()
self.search_input.clear()
def load_notes(self):
cursor = self.conn.cursor()
cursor.execute("SELECT id, date, note FROM notes ORDER BY date DESC")
rows = cursor.fetchall()
self.table.setRowCount(len(rows))
for row_idx, (id_, date, note) in enumerate(rows):
self.table.setItem(row_idx, 0, QTableWidgetItem(str(id_)))
self.table.setItem(row_idx, 1, QTableWidgetItem(date))
self.table.setItem(row_idx, 2, QTableWidgetItem(note))
def search_notes(self):
query = self.search_input.text().strip()
cursor = self.conn.cursor()
if query:
cursor.execute("""
SELECT n.id, n.date, n.note
FROM notes n
JOIN notes_fts f ON n.id = f.rowid
WHERE notes_fts MATCH ?
ORDER BY n.date DESC
""", (query,))
else:
cursor.execute("SELECT id, date, note FROM notes ORDER BY date DESC")
rows = cursor.fetchall()
self.table.setRowCount(len(rows))
for row_idx, (id_, date, note) in enumerate(rows):
self.table.setItem(row_idx, 0, QTableWidgetItem(str(id_)))
self.table.setItem(row_idx, 1, QTableWidgetItem(date))
self.table.setItem(row_idx, 2, QTableWidgetItem(note))
def edit_selected_note(self):
selected = self.table.selectedItems()
if not selected:
QMessageBox.warning(self, "Ошибка", "Выберите заметку для редактирования!")
return
row = self.table.currentRow()
note_id = self.table.item(row, 0).text()
current_note = self.table.item(row, 2).text()
new_note, ok = QInputDialog.getText(self, "Редактировать заметку", "Введите новую заметку:", text=current_note)
if ok and new_note.strip():
if len(new_note) > 255:
QMessageBox.warning(self, "Ошибка", "Заметка не может превышать 255 символов!")
return
cursor = self.conn.cursor()
cursor.execute("UPDATE notes SET note = ? WHERE id = ?", (new_note, note_id))
self.conn.commit()
self.load_notes()
def edit_note(self, row, column):
self.table.selectRow(row)
self.edit_selected_note()
def delete_note(self):
selected = self.table.selectedItems()
if not selected:
QMessageBox.warning(self, "Ошибка", "Выберите заметку для удаления!")
return
reply = QMessageBox.question(self, "Подтверждение", "Удалить выбранную заметку?",
QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
if reply == QMessageBox.Yes:
row = self.table.currentRow()
note_id = self.table.item(row, 0).text()
cursor = self.conn.cursor()
cursor.execute("DELETE FROM notes WHERE id = ?", (note_id,))
self.conn.commit()
self.load_notes()
def closeEvent(self, event):
self.conn.close()
event.accept()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = NotebookApp()
window.show()
sys.exit(app.exec_())