【问题标题】:How can I change color of part of the text in QLineEdit?如何更改 QLineEdit 中部分文本的颜色?
【发布时间】:2013-01-03 06:00:06
【问题描述】:

我想为 QLineEdit 中编写的文本添加一些语法突出显示,但它不支持富文本格式,我无法将 QlineEdit 更改为其他内容,所以我应该找到如何在此小部件中设置文本颜色。

有没有办法做到这一点?

【问题讨论】:

  • 很遗憾他们没有为此提供本机应用程序,一种类似于QTextEdit 的单行应用程序。 Summerfield 在他的 PyQt 书中,展示了如何在第 13 章中使用QTextEdit 作为基类来制作一个。

标签: c++ qt user-interface


【解决方案1】:

刚刚找到了一个巧妙的技巧。

static void setLineEditTextFormat(QLineEdit* lineEdit, const QList<QTextLayout::FormatRange>& formats)
{
    if(!lineEdit)
        return;

    QList<QInputMethodEvent::Attribute> attributes;
    foreach(const QTextLayout::FormatRange& fr, formats)
    {
        QInputMethodEvent::AttributeType type = QInputMethodEvent::TextFormat;
        int start = fr.start - lineEdit->cursorPosition();
        int length = fr.length;
        QVariant value = fr.format;
        attributes.append(QInputMethodEvent::Attribute(type, start, length, value));
    }
    QInputMethodEvent event(QString(), attributes);
    QCoreApplication::sendEvent(lineEdit, &event);
}

static void clearLineEditTextFormat(QLineEdit* lineEdit)
{
    setLineEditTextFormat(lineEdit, QList<QTextLayout::FormatRange>());
}

// Usage example:
QLineEdit* lineEdit = new QLineEdit;
lineEdit->setText(tr("Task Tracker - Entry"));

QList<QTextLayout::FormatRange> formats;

QTextCharFormat f;

f.setFontWeight(QFont::Bold);
QTextLayout::FormatRange fr_task;
fr_task.start = 0;
fr_task.length = 4;
fr_task.format = f;

f.setFontItalic(true);
f.setBackground(Qt::darkYellow);
f.setForeground(Qt::white);
QTextLayout::FormatRange fr_tracker;
fr_tracker.start = 5;
fr_tracker.length = 7;
fr_tracker.format = f;

formats.append(fr_task);
formats.append(fr_tracker);

setLineEditTextFormat(lineEdit, formats);

【讨论】:

    【解决方案2】:

    您可以使用style sheets更改颜色。

     QLineEdit* myLineEdit = new QLineEdit("Whatever");
    
     //for whatever case you want to change the color
     if(syntax_needs_to_highlighted)
          myLineEdit->setStyleSheet("QLineEdit#myLineEdit{color:blue}"); 
    

    对于这种情况,您可能需要考虑使用QTextBrowser

    【讨论】:

      【解决方案3】:

      您可以像这样更改文本的颜色:

      QLineEdit *line = new QLineEdit();
      line->setText("this is a test");
      line->setStyleSheet("foreground-color: blue;");
      

      如果不起作用,请将最后一行替换为以下内容:

      line->setStyleSheet("color: blue;");
      

      【讨论】:

      • 两者都不需要使用"color: blue;"(FWIW 使用 PySide)
      【解决方案4】:

      我可以通过在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)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-01-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-05
        • 2015-01-10
        • 1970-01-01
        相关资源
        最近更新 更多