#!/usr/bin/python # -*- coding: utf-8 -*- import sys from PyQt4.QtGui import * from PyQt4.QtCore import * from highlighter import MyHighlighter from highlighter import HighlightingRule class CodeEditor(QPlainTextEdit): def __init__(self, parent = None): QPlainTextEdit.__init__(self, parent) self.lineNumberArea = LineNumberArea(self) self.connect(self, SIGNAL('blockCountChanged(int)'), \ self.updateLineNumberAreaWidth) self.connect(self, SIGNAL('updateRequest(const QRect &, int)'), \ self.updateLineNumberArea) self.connect(self, SIGNAL('cursorPositionChanged()'), \ self.highlightCurrentLine) self.updateLineNumberAreaWidth(0) self.highlightCurrentLine() def highlightCurrentLine(self): extraSelections = QTextEdit.extraSelections(QTextEdit()) if not self.isReadOnly(): selection = QTextEdit.ExtraSelection() lineColor = QColor(Qt.yellow).lighter(160) selection.format.setBackground(lineColor) selection.format.setProperty(QTextFormat.FullWidthSelection, True) selection.cursor = self.textCursor() selection.cursor.clearSelection() extraSelections.append(selection) self.setExtraSelections(extraSelections) def lineNumberAreaWidth(self): digits = 1 Max = max(1, self.blockCount()) while (Max >= 10) : Max /= 10 digits += 1 space = 3 + self.fontMetrics().width('9') * digits return space def updateLineNumberAreaWidth(self, newBlockCount): self.setViewportMargins(self.lineNumberAreaWidth(), 0, 0, 0) def updateLineNumberArea(self, rect, dy): if dy: self.lineNumberArea.scroll(0, dy) else: self.lineNumberArea.update(0, rect.y(), \ self.lineNumberAreaWidth(), \ rect.height()) if (rect.contains(self.viewport().rect())): self.updateLineNumberAreaWidth(0) def resizeEvent(self, e): QPlainTextEdit.resizeEvent(self, e) cr = self.contentsRect() self.lineNumberArea.setGeometry(QRect(cr.left(), cr.top(), \ self.lineNumberAreaWidth(), \ cr.height())) def lineNumberAreaPaintEvent(self, event): painter = QPainter(self.lineNumberArea) rect = event.rect() painter.fillRect(rect, Qt.lightGray) block = self.firstVisibleBlock() blockNumber = block.blockNumber() top = int(self.blockBoundingGeometry(block).translated(\ self.contentOffset()).top()) bottom = top + int(self.blockBoundingRect(block).height()) while (block.isValid() and top <= rect.bottom()): if (block.isVisible() and bottom >= rect.top()): number = QString.number(blockNumber + 1) painter.setPen(Qt.black) painter.drawText(0, top, self.lineNumberArea.width(), \ self.fontMetrics().height(), \ Qt.AlignRight, number) block = block.next() top = bottom bottom = top + int(self.blockBoundingRect(block).height()) blockNumber += 1 class LineNumberArea(QWidget): def __init__(self, editor): QWidget.__init__(self, editor) self.codeEditor = editor def sizeHint(self): return QSize(codeEditor.lineNumberAreaWidth(), 0) def paintEvent(self, event): self.codeEditor.lineNumberAreaPaintEvent(event) def main(): app = QApplication(sys.argv) editor = CodeEditor() editor.setWindowTitle('Code Editor Example') editor.show() app.exec_() if __name__ == '__main__': main()