Reputation: 41
Using PySide/PyQT, I need to add some syntax highlighting to text being entered in a QLineEdit. I need to highlight specific key words.
I saw the post below with an example of how to do this in C++ but I'm trying to do it in Python. (Tried translating from C++ to Python but couldn't get it...) Anyone have a suggestion for how to do this in Python? Thanks.
How can I change color of part of the text in QLineEdit?
Further info:
Currently, I'm changing the color of the entire QLineEdit as follows:
for dupLineEd in duplicates[1]:
dupLineEd.setStyleSheet("QLineEdit{color:Khaki}")
This is not ideal. What I need to do is identify whether or not certain words within the QLineEdit meet a condition (in this case, whether they are duplicates of a word in another QLineEdit) and if so, then highlight only the word within the QLineEdit in a color, rather than the entire QLineEdit. This highlighting needs to be done live as the user is typing, so that for example as they complete a word, if the word meets the condition, the word turns yellow. The rest of the text in the QLineEdit does not change color.
Thanks in advance to anyone who may have any suggestions!
Upvotes: 2
Views: 1397
Reputation: 41
The best workaround I could find so far was to make a new class of QTextEdit that behaves (partly) like a QLineEdit.
For now I'm borrowing a Highligter class that works with QTextEdit, written by igor-bogomolov, posted on github here: https://github.com/pyside/Examples/blob/master/examples/richtext/syntaxhighlighter/syntaxhighlighter.py
My resulting functional code is as follows. (You'll need to define main_window depending on your environment.)
class qTextEditTestUI(QtGui.QDialog):
def __init__(self, parent=QtGui.QWidget):
# Inherit __init__
super(qTextEditTestUI, self).__init__(parent)
# Set object name and window title
self.setObjectName('qTextEditTestWindow')
self.setWindowTitle('qTextEdit Test Window')
# Window type (Qt.tool not Qt.Window)
self.setWindowFlags(QtCore.Qt.Tool)
# ATTRS
self.highlighter = Highlighter()
# CREATE WIDGETS
variableFormat = QtGui.QTextCharFormat()
#variableFormat.setFontWeight(QtGui.QFont.Bold)
variableFormat.setForeground(QtGui.QColor('Khaki'))
self.highlighter.addMapping('hello', variableFormat)
# Make a TextEdit
self.QTextEd = snglLnQTextEdit()
# Add the TextEdit's document to the highlighter
self.highlighter.addToDocument(self.QTextEd.document())
# SET MASTER LAYOUT
masterLayout = QtGui.QVBoxLayout()
self.setLayout(masterLayout)
# MASTER LAYOUT
masterLayout.addWidget(self.QTextEd)
masterLayout.addStretch()
## QLineEdit-Like QTextEdit
class snglLnQTextEdit(QtGui.QTextEdit):
def __init__(self, parent=None):
QtGui.QTextEdit.__init__(self, parent)
QTextEdFontMetrics = QtGui.QFontMetrics(self.font())
self.QTextEdRowHeight = QTextEdFontMetrics.lineSpacing()
self.setFixedHeight(2 * self.QTextEdRowHeight)
self.setLineWrapMode(QtGui.QTextEdit.NoWrap)
self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
# CONNECT WIDGET SIGNAL
self.textChanged.connect(self.validateCharacters)
def validateCharacters(self):
badChars = ['\n']
cursor = self.textCursor()
curPos = cursor.position()
for badChar in badChars:
origText = self.toPlainText()
for char in origText:
if char in badChars:
cleanText = origText.replace(char, '')
self.blockSignals(True)
self.setText(cleanText)
self.blockSignals(False)
cursor.setPosition(curPos-1)
self.setTextCursor(cursor)
## Highligher Class written by igor-bogomolov
class Highlighter(QtCore.QObject):
def __init__(self, parent=None):
QtCore.QObject.__init__(self, parent)
self.mappings = {}
def addToDocument(self, doc):
self.connect(doc, QtCore.SIGNAL('contentsChange(int, int, int)'), self.highlight)
def addMapping(self, pattern, format):
self.mappings[pattern] = format
def highlight(self, position, removed, added):
doc = self.sender()
block = doc.findBlock(position)
if not block.isValid():
return
if added > removed:
endBlock = doc.findBlock(position + added)
else:
endBlock = block
while block.isValid() and not (endBlock < block):
self.highlightBlock(block)
block = block.next()
def highlightBlock(self, block):
layout = block.layout()
text = block.text()
overrides = []
for pattern in self.mappings:
for m in re.finditer(pattern,text):
range = QtGui.QTextLayout.FormatRange()
s,e = m.span()
range.start = s
range.length = e-s
range.format = self.mappings[pattern]
overrides.append(range)
layout.setAdditionalFormats(overrides)
block.document().markContentsDirty(block.position(), block.length())
## Test Usage:
panl = qTextEditTestUI(parent=main_window())
panl.show()
This will get the job done but I'm not entirely happy with it; it feels clunky. I'm still hoping to work out how to do this kind of highlighting with a QLineEdit.
Upvotes: 2