April 01, 2011 at 08:25 Tags Python , Qt

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:

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

Update (15-May-2017): A new documentation site for the use of QScintilla with Python is available here.