Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How could I implement live markdown preview in the same text input box?

Tags:

python

pyqt

I'm building a note-taking GUI with QT Designer and Python. I'm envisioning something that saves the notes as *.txt files with simple markdown. For the GUI, however, I'd like the main text editing box to be able to render markdown live while you're in "edit mode" and typing away. So if you typed *italic* or **bold**, the text box would recognize this and italicize or bold it with those markdown symbols still in the text. Once you exit "edit mode," you'd be left with a preview of the note properly formatted with rich text and none of the markdown symbols. If anybody is familiar with Notable, I'm pretty much looking to replicate that (honorable mention would be the Bear app as well, but that functions differently in that it always stays in the "live preview" mode).

I'm trying to figure out how to go about this with QT and Python and this is all I could come up with so far:

  1. There's a example on the QT website that demonstrates a live preview using QWebEngineView, but that's side-by-side with a normal text box and not what I had in mind.

  2. I wonder if this could also be implemented with some sort of syntax highlighting? So in that sense, I'd be building more a code editor or something? So the QT text box would be configured (as rich text or HTML? I don't know) so that any instances of *(italic text)* would get the italicized formatting the moment you finished typing that second asterisk. I guess in the syntax highlighting definition, I'd be able to use some sort of wildcard character to say "anything between these markdown symbols?"

Does anybody have any suggestions on a solution?

like image 627
mangopeaches Avatar asked Sep 06 '25 03:09

mangopeaches


1 Answers

Since Qt 5.14 QTextEdit supports the markdown format so you can use 2 QTextEdit that show the different editing modes. To swap the QTextEdit you can use a QStackedWidget:

from PyQt5 import QtCore, QtGui, QtWidgets


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.stacked_widget = QtWidgets.QStackedWidget()
        self.setCentralWidget(self.stacked_widget)

        self.markdown_editor = QtWidgets.QTextEdit()
        self.markdown_viewer = QtWidgets.QTextEdit(readOnly=True)

        self.stacked_widget.addWidget(self.markdown_editor)
        self.stacked_widget.addWidget(self.markdown_viewer)

        foo_menu = self.menuBar().addMenu("&FooMenu")
        self.edit_action = foo_menu.addAction("&Edit")
        self.edit_action.setCheckable(True)
        self.edit_action.triggered.connect(self.handle_edit_mode)

    def handle_edit_mode(self):
        self.stacked_widget.setCurrentWidget(
            self.markdown_viewer
            if self.edit_action.isChecked()
            else self.markdown_editor
        )
        if self.stacked_widget.currentWidget() == self.markdown_viewer:
            self.markdown_viewer.setMarkdown(self.markdown_editor.toPlainText())


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)

    w = MainWindow()
    w.show()

    sys.exit(app.exec_())
like image 169
eyllanesc Avatar answered Sep 07 '25 21:09

eyllanesc