Sample using QScintilla with PyQt

April 1st, 2011 at 8:25 am

QScintilla is (a port to Qt of the Scintilla source code editor control) comes packaged with PyQt. Unfortunately, its documentation is quite scarce and it’s hard to find examples online.

So I developed a small sample editor with PyQt using QScintilla, which can serve as a starting point for more complex uses.

Here’s a screenshot:

http://eli.thegreenplace.net/wp-content/uploads/2011/03/qscintilla_sample_screenshot.png

The sample demonstrates some interesting features of QScintilla:

  • Syntax highlighting, and customizing how some of its styles look
  • Using the margin to show line numbers
  • Clickable markers on the margin (can be used for breakpoints in a debugger, code bookmarks, error marks, or any other purpose)
  • Enabling brace matching
  • Setting a background color for the current line

Here’s the complete code:

#-------------------------------------------------------------------------
# qsci_simple_pythoneditor.pyw
#
# QScintilla sample with PyQt
#
# Eli Bendersky (eliben@gmail.com)
# This code is in the public domain
#-------------------------------------------------------------------------
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.Qsci import QsciScintilla, QsciLexerPython


class SimplePythonEditor(QsciScintilla):
    ARROW_MARKER_NUM = 8

    def __init__(self, parent=None):
        super(SimplePythonEditor, self).__init__(parent)

        # Set the default font
        font = QFont()
        font.setFamily('Courier')
        font.setFixedPitch(True)
        font.setPointSize(10)
        self.setFont(font)
        self.setMarginsFont(font)

        # Margin 0 is used for line numbers
        fontmetrics = QFontMetrics(font)
        self.setMarginsFont(font)
        self.setMarginWidth(0, fontmetrics.width("00000") + 6)
        self.setMarginLineNumbers(0, True)
        self.setMarginsBackgroundColor(QColor("#cccccc"))

        # Clickable margin 1 for showing markers
        self.setMarginSensitivity(1, True)
        self.connect(self,
            SIGNAL('marginClicked(int, int, Qt::KeyboardModifiers)'),
            self.on_margin_clicked)
        self.markerDefine(QsciScintilla.RightArrow,
            self.ARROW_MARKER_NUM)
        self.setMarkerBackgroundColor(QColor("#ee1111"),
            self.ARROW_MARKER_NUM)

        # Brace matching: enable for a brace immediately before or after
        # the current position
        #
        self.setBraceMatching(QsciScintilla.SloppyBraceMatch)

        # Current line visible with special background color
        self.setCaretLineVisible(True)
        self.setCaretLineBackgroundColor(QColor("#ffe4e4"))

        # Set Python lexer
        # Set style for Python comments (style number 1) to a fixed-width
        # courier.
        #
        lexer = QsciLexerPython()
        lexer.setDefaultFont(font)
        self.setLexer(lexer)
        self.SendScintilla(QsciScintilla.SCI_STYLESETFONT, 1, 'Courier')

        # Don't want to see the horizontal scrollbar at all
        # Use raw message to Scintilla here (all messages are documented
        # here: http://www.scintilla.org/ScintillaDoc.html)
        self.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0)

        # not too small
        self.setMinimumSize(600, 450)

    def on_margin_clicked(self, nmargin, nline, modifiers):
        # Toggle marker for the line the margin was clicked on
        if self.markersAtLine(nline) != 0:
            self.markerDelete(nline, self.ARROW_MARKER_NUM)
        else:
            self.markerAdd(nline, self.ARROW_MARKER_NUM)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    editor = SimplePythonEditor()
    editor.show()
    editor.setText(open(sys.argv[0]).read())
    app.exec_()

As I said, the documentation for QScintilla is far from being abundant. I used the following sources to develop the sample:

  • QScintilla class hierarchy – this auto-generated documentation is the closest you get to a reference for the module
  • Scintilla itself is a control that communicates with the outer world via messages. The QsciScintilla.SendScintilla method allows to send the messages, which are quite well documented in the low-level Scintilla Documentation.

Note that I’m using the QsciLexerPython lexer for Python source code highlighting. Scintilla supports lexers for many languages (and others can be easily supported by playing with the settings of existing lexers for similar languages). For a complete list of lexers supported, run:

import PyQt4.Qsci

for sym in dir(PyQt4.Qsci):
    if sym.startswith('QsciLexer'):
        print sym

Related posts:

  1. Code sample – socket client based on Twisted with PyQt
  2. Passing extra arguments to PyQt slots
  3. New-style signal-slot connection mechanism in PyQt
  4. Creating splash screens in PyQt
  5. Code sample – socket client thread in Python

9 Responses to “Sample using QScintilla with PyQt”

  1. Virgil DuprasNo Gravatar Says:

    Thanks, just two days ago, I was entertaining the thought of playing with QScintilla a bit. This post is an omen: now I have to :)

  2. RobertNo Gravatar Says:

    How big is that including what you need for Qt?

  3. elibenNo Gravatar Says:

    Robert,

    Not sure what you mean by “how big”? It’s a Python script that runs when you have PyQt installed. PyQt bundles both the Qt DLLs and QScintilla

  4. NicolasNo Gravatar Says:

    Really nice.

    Thanks a lot !

  5. AbhiNo Gravatar Says:

    I HAVE TO INTEGRATE A CODE WRITTEN FOR CAMERA CALIBRATION INTO PYQT I HAVE DESIGNED THE INTERFACE FOR THE GUI AS TO HOW IT SHOULD LOOK BUT I HAVE TO AUTOMATICALL CALIBARTE THE CAMERAS USING GUI.CAN ANYONE PLEASE TELL ME HOW TO GO ABOUT AS TO I AM VERY NEW TO THIS

  6. Titus BarikNo Gravatar Says:

    Looks like the link to “QScintilla class hierarchy” is no longer functional. Can the link be updated to the new resource? Thanks!

  7. Tcll5850No Gravatar Says:

    interesting, clean, and simple… I leik it :3

    can it be made to collapse text??
    (SciTE could collapse classes, functions, and if statements)

    credit to you in UMC_SIDE for this. ;3

  8. Tcll5850No Gravatar Says:

    @my question: Yes it can :)

    found this reference for ya: http://pyqt.sourceforge.net/Docs/QScintilla2/classQsciScintilla.html

    this is cool, and SOOO much simpler than my methods using a QTextEdit widget.
    very nice :)

  9. Tcll5850No Gravatar Says:

    just found this: http://kib2.free.fr/tutos/PyQt4/QScintilla2.html
    which is basically the same thing as yours with extensions.

    well, if anyone just needs a simple editor, then you’re on the right page :)

Leave a Reply

To post code with preserved formatting, enclose it in `backticks` (even multiple lines)