PyQt5: How to change input text color based on keypress (macro)?

53 Views Asked by At

I created a very basic text editor in PyQt5 (code below).

How would I go about inserting code that would allow the color of the text being typed to change on a keystroke (like a macro)?

Imagine you're typing like a normal notepad file, then you want each sentence to be able to change colors based on keyboard input.

Example:

(black) - Hello world,

keystroke of some kind, macro

(text switches to red) - how are you today?

keystroke

(text switched to blue) - I'm good thanks, how are you?

etc...

# Let's import some libraries

import sys
import os
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtPrintSupport import *

# Have some class...

class MainWindow(QMainWindow):

# The constructor

def __init__(self, *args, **kwargs):
    super(MainWindow, self).__init__(*args, **kwargs)

    # Set a few parameters

    self.setGeometry(200, 200, 1600, 1200)
    layout = QVBoxLayout()
    self.editor = QPlainTextEdit()
    fixedfont = QFontDatabase.systemFont(QFontDatabase.FixedFont)
    fixedfont.setPointSize(14)
    self.editor.setFont(fixedfont)
    self.path = None

    # This is the editor

    layout.addWidget(self.editor)
    container = QWidget()
    container.setLayout(layout)
    self.setCentralWidget(container)
    self.status = QStatusBar()
    self.setStatusBar(self.status)
    
    # File menu

    file_menu = self.menuBar().addMenu("&File")

    open_file_action = QAction("Open file", self)
    open_file_action.setStatusTip("Open file")
    open_file_action.triggered.connect(self.file_open)
    file_menu.addAction(open_file_action)

    save_file_action = QAction("Save", self)
    save_file_action.setStatusTip("Save current entry")
    save_file_action.triggered.connect(self.file_save)
    file_menu.addAction(save_file_action)

    saveas_file_action = QAction("Save As", self)
    saveas_file_action.setStatusTip("Save current entry as (name)")
    saveas_file_action.triggered.connect(self.file_saveas)
    file_menu.addAction(saveas_file_action)

    # Setting wrapped text as default

    wrap_action = QAction("Wrap text", self)
    wrap_action.setChecked(True)

    # Update call

    self.update_title()
    self.show()

# Error dialog

def dialog_critical(self, s):

    dlg = QMessageBox(self)
    dlg.setText(s)
    dlg.setIcon(QMessageBox.Critical)
    dlg.show()

# Action definitions

def file_open(self):

    path, _ = QFileDialog.getOpenFileName(self, "Open file", "", "Text documents (*.txt);All files (*.*)")
    if path:
        try:
            with open(path, 'r') as f:
                text = f.read()
        except Exception as e:
            self.dialog_critical(str(e))
        else:
            self.path = path
            self.editor.setPlainText(text)
            self.update_title()

def file_save(self):
    if self.path is None:
       return self.file_saveas()
    self._save_to_path(self.path)

def file_saveas(self):
    path, _ = QFileDialog.getSaveFileName(self, "Save file", "", "Text documents (*.txt);All files (*.*)")
    if not path:
        return
    self._save_to_path(path)

def _save_to_path(self, path):
    text = self.editor.toPlainText()
    try:
        with open(path, 'w') as f:
            f.write(text)
    except Exception as e:
        self.dialog_critical(str(e))
    else:
        self.path = path
        self.update_title()

def update_title(self):
    self.setWindowTitle("%s - Thought Journal" %(os.path.basename(self.path)
                                                 if self.path else "Untitled"))

def edit_toggle_wrap(self):
    self.editor.setLineWrapMode(1 if self.editor.lineWrapMode() == 0 else 0)

# Driver

if name == 'main':
app = QApplication(sys.argv)
app.setApplicationName("Thought-Journal-v1")
window = MainWindow()
app.exec_()

# End of program
1

There are 1 best solutions below

1
Sen ZmaKi On

This is a child class of QTextEdit that stores shorcuts/macros along with their corresponding colors such that when the shortcut keys are pressed, the text henceforth changes to the bound color.

class ShorcutColorEditor(QTextEdit):
    def __init__(self, parent: QWidget | None = None, keys_and_colors: list[tuple[str | QKeySequence, QColor]] | None = None) -> None:
        super().__init__(parent)
        self.shorcuts_and_colors: list[tuple[QShortcut, QColor]] = []
        if keys_and_colors:
            for k, c in keys_and_colors:
                s = QShortcut(QKeySequence(k), self)
                s.activated.connect(lambda c=c: self.setTextColor(c))
                self.shorcuts_and_colors.append((s, c))
# Example of usage
editor = ShorcutColorEditor(
            self, [("Ctrl+R", QColor("red")), ("Ctrl+B", QColor("blue"))])