#!/usr/bin/env python # -*- coding: utf-8 -*- """QPlainTextEdit With In Line Spell Check Source: https://nachtimwald.com/2009/08/22/qplaintextedit-with-in-line-spell-check/ """ __license__ = 'MIT' __author__ = '2009, John Schember ' __docformat__ = 'restructuredtext en' import re import sys import enchant from PyQt4.Qt import (QAction, QApplication, QMenu, QPlainTextEdit, QSyntaxHighlighter, QTextCharFormat, QTextCursor, Qt) from PyQt4.QtCore import pyqtSignal class SpellTextEdit(QPlainTextEdit): """QPlainTextEdit subclass which does spell-checking using PyEnchant""" def __init__(self, *args): QPlainTextEdit.__init__(self, *args) # Default dictionary based on the current locale. self.sp_dict = enchant.Dict() self.highlighter = Highlighter(self.document()) self.highlighter.setDict(self.sp_dict) def contextMenuEvent(self, event): """Custom context menu handler to add a spelling suggestions submenu""" popup_menu = self.createStandardContextMenu() # Select the word under the cursor. cursor = self.cursorForPosition(event.pos()) cursor.select(QTextCursor.WordUnderCursor) self.setTextCursor(cursor) # Check if the selected word is misspelled and offer spelling # suggestions if it is. if cursor.hasSelection(): text = unicode(cursor.selectedText()) if not self.sp_dict.check(text): spell_menu = QMenu('Spelling Suggestions') for word in self.sp_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): """QSyntaxHighlighter subclass which consults a PyEnchant dictionary""" WORDS = ur'(?iu)[\w\']+' def __init__(self, *args): QSyntaxHighlighter.__init__(self, *args) self.sp_dict = None def setDict(self, sp_dict): """Sets the spelling dictionary to be used""" self.sp_dict = sp_dict def highlightBlock(self, text): """Overridden QSyntaxHighlighter method to apply the highlight""" if not self.sp_dict: return text = unicode(text) char_format = QTextCharFormat() char_format.setUnderlineColor(Qt.red) char_format.setUnderlineStyle(QTextCharFormat.SpellCheckUnderline) for word_object in re.finditer(self.WORDS, text): # Don't spell-check purely numeric "words" if word_object.group().isdigit(): continue if not self.sp_dict.check(word_object.group()): self.setFormat(word_object.start(), word_object.end() - word_object.start(), char_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()))) if __name__ == '__main__': app = QApplication(sys.argv) spellEdit = SpellTextEdit() spellEdit.show() sys.exit(app.exec_())