我可以通过在QLineEdit 上覆盖QLabel 然后将行的文本颜色编辑为白色来实现此目的。当textEdited 信号发出时,使用它来更新QLabel 的文本。 QLabel 接受富文本,因此您可以处理 QLineEdit 中的文本,并将关键字替换为所需的 HTML,以便以您想要的方式显示文本。我相信您可以修改代码以更改当前选择的文本颜色。
class LabelEditPair(QLineEdit):
"""
QLineEdit that changes the color of the word 'blue' to blue and
the changes the font weight of the word 'bold' to bold.
"""
def __init__(self):
super().__init__()
self.label = QLabel("starting out")
self.label.setParent(self)
self.label.move(3, 0)
self.label.setAttribute(Qt.WA_TransparentForMouseEvents)
self.setStyleSheet("QLineEdit{color: white}")
self.textEdited.connect(self.text_edited)
def resizeEvent(self, event):
self.label.setFixedHeight(self.height())
self.label.setFixedWidth(self.width())
super().resizeEvent(event)
def text_edited(self, text):
text = text.replace("blue", "<span style='color: blue'>blue</span>")
text = text.replace("bold", "<span style='font-weight: bold'>bold</span>")
self.label.setText(text)
编辑
上一个示例在文本从QLineEdit 小部件溢出的情况下效果不佳。这是一个更全面的小部件,它使用相同的想法,但不是创建QLineEdit 的子类,而是使用QLineEdit 和两个QLabels 的子类QFrame,一个在光标之前,一个在光标之后。该小部件将正则表达式匹配替换为 HTML 以更改这些字符的样式。
class LabelEditPair(QFrame):
"""
QLineEdit that changes the color of the word 'blue' to blue and
the changes the font weight of the word 'bold' to bold.
"""
def __init__(self, initial_text: str):
super().__init__()
self.stylized_regex: List[Tuple[str, str]] = []
self.setFixedHeight(22)
self.setObjectName("frame")
self.setStyleSheet("QFrame#frame{background-color: white; border: 1px solid gray}"
"QFrame:hover#frame{border: 1px solid black}"
"QFrame:selected#frame{border: 1px solid blue}")
self.setFrameStyle(QFrame.Box)
self.line_edit = QLineEdit(initial_text)
self.line_edit.setParent(self)
self.line_edit.move(0, 2)
self.line_edit.setStyleSheet("border: 0px solid white; background-color:transparent")
self.line_edit.setFixedWidth(2**16)
self.left_label = QLabel()
self.left_label.setParent(self.line_edit)
self.left_label.move(1, 1)
self.left_label.setAlignment(Qt.AlignRight)
self.left_label.setAttribute(Qt.WA_TransparentForMouseEvents)
self.right_label = QLabel()
self.right_label. setParent(self.line_edit)
self.right_label.move(5, 1)
self.right_label.setAlignment(Qt.AlignLeft)
self.right_label.setAttribute(Qt.WA_TransparentForMouseEvents)
self.right_label.setFixedWidth(2**16)
self.offset = 0
self.line_edit.textEdited.connect(self.text_edited)
self.line_edit.cursorPositionChanged.connect(self.apply_shift)
self.line_edit.selectionChanged.connect(self.set_text_to_update)
self.update_text_needed = True
self.placeholder = ""
self.color = (0, 0, 0)
def text(self):
return self.line_edit.text()
def setReadOnly(self, read_only: bool):
self.line_edit.setReadOnly(read_only)
self.line_edit.setAttribute(Qt.WA_TransparentForMouseEvents, read_only)
self.line_edit.end(False)
def set_placeholder_text(self, text: str):
self.placeholder = text
def set_text_color(self, color: Tuple[int, int, int]):
self.color = color
def set_text_to_update(self):
self.update_text_needed = True
def text_edited(self, text: str):
if len(text) == 0:
self.left_label.setText(self.placeholder)
self.left_label.setStyleSheet("color: gray")
return
self.left_label.setStyleSheet(f"color: rbg{self.color}")
new = self.line_edit.cursorPosition()
left_text = text[:new]
right_text = text[new:]
self.left_label.setText(left_text)
self.right_label.setText(right_text)
for style, regex in self.stylized_regex:
matches = findall(regex, left_text)
for match in matches:
left_text = left_text.replace(match, f"<span style='{style}'>{match}</span>")
self.left_label.setText(left_text)
matches_right = findall(regex, right_text)
for match in matches_right:
right_text = right_text.replace(match, f"<span style='{style}'>{match}</span>")
self.right_label.setText(right_text)
self.update_text_needed = False
def add_style_for_regex(self, style: str, regex: str):
self.stylized_regex.append((style, regex))
def apply_shift(self, old=None, new=None):
text = self.line_edit.text()
rect = self.line_edit.cursorRect()
x_pos = rect.x()
if x_pos + self.offset > self.width() - 8 and new == old + 1:
self.offset = -1*(x_pos - (self.width()-8))
elif new + 1 == old and x_pos + self.offset < self.width() * 1/2:
self.offset += 5
self.offset = min(0, self.offset)
if len(text) == 0:
self.offset = 0
self.line_edit.move(self.offset, 2)
self.left_label.setFixedWidth(x_pos + 4)
self.right_label.move(x_pos + 5, 1)
if self.update_text_needed:
self.text_edited(text=text)
self.update_text_needed = True
示例用法
self.color_edit = LabelEditPair("")
self.color_edit.add_style_for_regex("color: blue", "(?:HI|HELLO)")
main_layout.addWidget(self.color_edit)