Posts Tagged ‘spell check’
* QPlainTextEdit With In Line Spell Check
Posted on August 22nd, 2009 by John. Filed under programming.
***Update: Simplified Highlighter.highlightBlock function
One thing Qt lacks is an integrated spell check in the text entry components. For a project I’m working on this is necessary. Using python-enchant and the QSyntaxHighlighter I was able to implement this functionality. Here is how to add an in line spell check support to a QPlainTextEdit.
#!/usr/bin/env python # -*- coding: utf-8 -*- __license__ = 'MIT' __copyright__ = '2009, John Schember ' __docformat__ = 'restructuredtext en' import re import sys import enchant from PyQt4.Qt import QAction from PyQt4.Qt import QApplication from PyQt4.Qt import QEvent from PyQt4.Qt import QMenu from PyQt4.Qt import QMouseEvent from PyQt4.Qt import QPlainTextEdit from PyQt4.Qt import QSyntaxHighlighter from PyQt4.Qt import QTextCharFormat from PyQt4.Qt import QTextCursor from PyQt4.Qt import Qt from PyQt4.QtCore import pyqtSignal class SpellTextEdit(QPlainTextEdit): def __init__(self, *args): QPlainTextEdit.__init__(self, *args) # Default dictionary based on the current locale. self.dict = enchant.Dict() self.highlighter = Highlighter(self.document()) self.highlighter.setDict(self.dict) def mousePressEvent(self, event): if event.button() == Qt.RightButton: # Rewrite the mouse event to a left button event so the cursor is # moved to the location of the pointer. event = QMouseEvent(QEvent.MouseButtonPress, event.pos(), Qt.LeftButton, Qt.LeftButton, Qt.NoModifier) QPlainTextEdit.mousePressEvent(self, event) def contextMenuEvent(self, event): popup_menu = self.createStandardContextMenu() # Select the word under the cursor. cursor = self.textCursor() cursor.select(QTextCursor.WordUnderCursor) self.setTextCursor(cursor) # Check if the selected word is misspelled and offer spelling # suggestions if it is. if self.textCursor().hasSelection(): text = unicode(self.textCursor().selectedText()) if not self.dict.check(text): spell_menu = QMenu('Spelling Suggestions') for word in self.dict.suggest(text): action = SpellAction(word, spell_menu) action.correct.connect(self.correctWord) spell_menu.addAction(action) # Only add the spelling suggests to the menu if there are # suggestions. if len(spell_menu.actions()) != 0: popup_menu.insertSeparator(popup_menu.actions()[0]) popup_menu.insertMenu(popup_menu.actions()[0], spell_menu) popup_menu.exec_(event.globalPos()) def correctWord(self, word): ''' Replaces the selected text with word. ''' cursor = self.textCursor() cursor.beginEditBlock() cursor.removeSelectedText() cursor.insertText(word) cursor.endEditBlock() class Highlighter(QSyntaxHighlighter): WORDS = u'(?iu)[\w\']+' def __init__(self, *args): QSyntaxHighlighter.__init__(self, *args) self.dict = None def setDict(self, dict): self.dict = dict def highlightBlock(self, text): if not self.dict: return text = unicode(text) format = QTextCharFormat() format.setUnderlineColor(Qt.red) format.setUnderlineStyle(QTextCharFormat.SpellCheckUnderline) for word_object in re.finditer(self.WORDS, text): if not self.dict.check(word_object.group()): self.setFormat(word_object.start(), word_object.end() - word_object.start(), format) class SpellAction(QAction): ''' A special QAction that returns the text in a signal. ''' correct = pyqtSignal(unicode) def __init__(self, *args): QAction.__init__(self, *args) self.triggered.connect(lambda x: self.correct.emit( unicode(self.text()))) def main(args=sys.argv): app = QApplication(args) spellEdit = SpellTextEdit() spellEdit.show() return app.exec_() if __name__ == '__main__': sys.exit(main())
The SpellTextEdit’s purpose is straightforward. It will mark misspelled words. Right clicking on a word in the SpellTextEdit will cause the word to become selected and display a context menu. If the word is misspelled and there are spelling suggestions the context menu will include a sub menu of those suggestions. Selecting a suggestion will replace the misspelled text with the selection.
The Highlighter class takes text, breaks it into words, checks if they are spelled correctly and if not underlines the misspelled ones with a red squiggle. I’m using a regular expression to split the words instead of using str.split because str.split will only split on whitespace and include punctuation (e.g. “.!*) as part of the words.
SpellAction is a simple class that allows for the action’s text to be sent with the signal. This is necessary for dynamically creating the list of possible correction words in the right click menu. The SpellAction is connected to a function that replaces the selected text with the signal text.
Tags
Archives
- January 2012 (3)
- December 2011 (2)
- November 2011 (1)
- October 2011 (3)
- September 2011 (9)
- August 2011 (15)
- July 2011 (5)
- June 2011 (3)
- May 2011 (4)
- April 2011 (2)
- March 2011 (2)
- February 2011 (4)
- January 2011 (4)
- December 2010 (2)
- November 2010 (1)
- October 2010 (1)
- August 2010 (3)
- 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)