* Better QPlainTextEdit With Line Numbers
Posted on August 19th, 2009 by John. Filed under programming.
My last post was an implementation of a Qt widget which displays text with line numbers. I found that it has a few limitations. The biggest was a performance penalty when dealing with large documents. I’ve since re-factored and rewritten the class to make the performance acceptable. I’ve also cleaned up the code a bit and added a highlight to the current line.
''' Text widget with support for line numbers ''' from PyQt4.Qt import QFrame from PyQt4.Qt import QHBoxLayout from PyQt4.Qt import QPainter from PyQt4.Qt import QPlainTextEdit from PyQt4.Qt import QRect from PyQt4.Qt import QTextEdit from PyQt4.Qt import QTextFormat from PyQt4.Qt import QVariant from PyQt4.Qt import QWidget from PyQt4.Qt import Qt class LNTextEdit(QFrame): class NumberBar(QWidget): def __init__(self, edit): QWidget.__init__(self, edit) self.edit = edit self.adjustWidth(1) def paintEvent(self, event): self.edit.numberbarPaint(self, event) QWidget.paintEvent(self, event) def adjustWidth(self, count): width = self.fontMetrics().width(unicode(count)) if self.width() != width: self.setFixedWidth(width) def updateContents(self, rect, scroll): if scroll: self.scroll(0, scroll) else: # It would be nice to do # self.update(0, rect.y(), self.width(), rect.height()) # But we can't because it will not remove the bold on the # current line if word wrap is enabled and a new block is # selected. self.update() class PlainTextEdit(QPlainTextEdit): def __init__(self, *args): QPlainTextEdit.__init__(self, *args) #self.setFrameStyle(QFrame.NoFrame) self.setFrameStyle(QFrame.NoFrame) self.highlight() #self.setLineWrapMode(QPlainTextEdit.NoWrap) self.cursorPositionChanged.connect(self.highlight) def highlight(self): hi_selection = QTextEdit.ExtraSelection() hi_selection.format.setBackground(self.palette().alternateBase()) hi_selection.format.setProperty(QTextFormat.FullWidthSelection, QVariant(True)) hi_selection.cursor = self.textCursor() hi_selection.cursor.clearSelection() self.setExtraSelections([hi_selection]) def numberbarPaint(self, number_bar, event): font_metrics = self.fontMetrics() current_line = self.document().findBlock(self.textCursor().position()).blockNumber() + 1 block = self.firstVisibleBlock() line_count = block.blockNumber() painter = QPainter(number_bar) painter.fillRect(event.rect(), self.palette().base()) # Iterate over all visible text blocks in the document. while block.isValid(): line_count += 1 block_top = self.blockBoundingGeometry(block).translated(self.contentOffset()).top() # Check if the position of the block is out side of the visible # area. if not block.isVisible() or block_top >= event.rect().bottom(): break # We want the line number for the selected line to be bold. if line_count == current_line: font = painter.font() font.setBold(True) painter.setFont(font) else: font = painter.font() font.setBold(False) painter.setFont(font) # Draw the line number right justified at the position of the line. paint_rect = QRect(0, block_top, number_bar.width(), font_metrics.height()) painter.drawText(paint_rect, Qt.AlignRight, unicode(line_count)) block = block.next() painter.end() def __init__(self, *args): QFrame.__init__(self, *args) self.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken) self.edit = self.PlainTextEdit() self.number_bar = self.NumberBar(self.edit) hbox = QHBoxLayout(self) hbox.setSpacing(0) hbox.setMargin(0) hbox.addWidget(self.number_bar) hbox.addWidget(self.edit) self.edit.blockCountChanged.connect(self.number_bar.adjustWidth) self.edit.updateRequest.connect(self.number_bar.updateContents) def getText(self): return unicode(self.edit.toPlainText()) def setText(self, text): self.edit.setPlainText(text) def isModified(self): return self.edit.document().isModified() def setModified(self, modified): self.edit.document().setModified(modified) def setLineWrapMode(self, mode): self.edit.setLineWrapMode(mode)
8 Responses to “Better QPlainTextEdit With Line Numbers”
Leave a Reply
Tags
bash
batteries
bookeen
c++
calibre
cats
cover
cybook
device interfaces
ebook
electronics
epub
eReader
ezreader pocket pro
fb2
gadgets
GeR2
google
GUI
image
json
KDocker
kindle
Linux
markdown
mobi
N770
nook
palmdoc
pdb
pdf
pgm
pml
pmlz
pocket pro
pyqt
python
qt
rb
release
thumbnail
txt
x11
xlib
ztxt
Archives
- July 2010 (4)
- June 2010 (1)
- May 2010 (2)
- March 2010 (1)
- January 2010 (8)
- December 2009 (5)
- November 2009 (6)
- October 2009 (4)
- September 2009 (2)
- August 2009 (6)
- July 2009 (6)
- June 2009 (4)
- May 2009 (6)
- April 2009 (4)
- March 2009 (2)
- February 2009 (4)
- January 2009 (4)
- December 2008 (7)
- November 2008 (2)
March 12th, 2010 at 4:30 am
Hi. Thanks for the code. It is really helpful.
One question: In the highlight function, shouldn’t the line
hi_selection.format.setBackground(self.palette().alternateBase())
be
hi_selection[0].format.setBackground(self.palette().alternateBase())
since
QTextEdit.ExtraSelection()
is supposed to return a QList??
Thanks
May 16th, 2010 at 8:59 pm
The docs do say it return a list… However, it doesn’t return an indexable list. The posted code works correctly. Using hi_selection[0] will result in:
June 23rd, 2010 at 2:05 pm
Thank YOU !!! This is the basis of a latex editor im trying to will … I Added bracket matching to your code….
code removed by request of the author.
June 23rd, 2010 at 3:20 pm
sorry!!! the code has some errors! I am working on it… Id like to know how to post highlighted/indented code here!!!
June 23rd, 2010 at 6:02 pm
<pre lang=”python”>
code…
</pre>
I add it for you in the code comment.
June 23rd, 2010 at 7:08 pm
Thank you again, now for your quick reply! It might be better if you remove the code… I promise that once i finish the basic editor i’ll post the code again, but i was actually too happy cause the code worked fine that didnt give my self a chance to test it… and it is not completely correct… Sorry for my bad english.
June 26th, 2010 at 10:36 am
June 26th, 2010 at 10:41 am
This one is OK!!! but it’s kind of slow when there are several brackets in the same block… if you get a better idea ill be grateful… This implementation of QTextBlockUserData is actually from the QtQuarterly. As you see, the key bindings for compiling a document, opening, saving and stuff, are already defined by an event filter but the only emit signals and do nothing else.