首页 文章

可编辑的多色QLineEdit

提问于
浏览
7

我知道您可以更改行编辑的颜色,只要所有文本都是相同的颜色,但是可以为字符分配不同的颜色吗?也就是说,有些字符是红色的,有些是黑色的,或者只是每个字符都有不同的颜色 .

这里有一个类似的问题 - How can I change color of part of the text in QLineEdit?,但在我的情况下还有一个额外的约束 - QLineEdit必须在编辑时保留颜色位置,而输入的新文本假定某些默认颜色 . 另一个问题没有那个限制 .

它有点有用,但颜色与文本分离 - 当你编辑行编辑时,恰好在给定位置的符号假定该位置的颜色和格式 . 那就是 the formatting is not anchored to the text . 这里有两个截图,看看我在说什么:

enter image description here

enter image description here

我将自己解决这个缺点,当我准备好时,我会将结果作为答案发布 .

我会通过订阅 textEdited() 信号或直接处理输入事件来做到这一点 . 每次更改文本时,我都会将颜色位置同步到它 .

与此同时,如果有人知道我错过了一个非常简单的解决方案,或者更容易解决问题,请随时分享 .

1 回答

  • 4

    我最后通过跟踪光标位置,最后一个选择开始和长度以及最后一个文本大小来实现它 . 当发出 textEdited() 信号时,我使用它们来确定插入和/或删除的文本,然后重放颜色数组中的插入和/或删除,以便将其同步到文本 .

    您可以指定用于用户插入的文本的颜色 . 如果未指定,将使用系统默认值,具体取决于系统主题 .

    唯一的问题是 it doesn't support Undo ,因为我不知道如何区分 textEdited() 信号是否是由撤销操作引起的 .


    ColorLineEdit.h

    #ifndef COLORLINEEDIT_H
    #define COLORLINEEDIT_H
    
    #include <QLineEdit>
    
    class ColorLineEdit : public QLineEdit
    {
        Q_OBJECT
    public:
        explicit ColorLineEdit(QWidget *parent = 0);
        void setCharColors(const QList<QColor> &colors = QList<QColor>());
        void setColorForInsertedText(const QColor &colorForInsertedText) { this->colorForInsertedText = colorForInsertedText; }
    
    signals:
    
    private slots:
        void onSelectionChanged();
        void onTextEdited(const QString &text);
    
    private:
        int lastTextSize;
        QList<QColor> colors;
        QColor colorForInsertedText;
        int lastSelectedTextSize;
        int lastSelectionStart;
    };
    
    #endif // COLORLINEEDIT_H
    

    ColorLineEdit.cpp

    #include "colorlineedit.h"
    #include <QTextLayout>
    
    ColorLineEdit::ColorLineEdit(QWidget *parent) :
        QLineEdit(parent)
    {
        connect(this, SIGNAL(selectionChanged()), SLOT(onSelectionChanged()));
        connect(this, SIGNAL(textEdited(QString)), SLOT(onTextEdited(QString)));
        lastSelectedTextSize = 0;
        lastSelectionStart = -1;
        lastTextSize = 0;
    }
    
    void ColorLineEdit::setCharColors(const QList<QColor> &colors)
    {
        // See http://stackoverflow.com/questions/14417333/how-can-i-change-color-of-part-of-the-text-in-qlineedit.
        QList<QInputMethodEvent::Attribute> attributes;
        int size = colors.size();
        attributes.reserve(size);
        for (int ii = 0; ii < size ; ii++) {
            if (colors[ii].isValid()) {
                QTextCharFormat charFormat;
                charFormat.setForeground(QBrush(colors[ii]));
                const int start = ii - cursorPosition();
                const int length = 1;
                attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, start, length, charFormat));
            }
        }
    
        QLineEdit::inputMethodEvent(&QInputMethodEvent(QString(), attributes));
    
        lastTextSize = text().size();
        this->colors = colors;
    }
    
    void ColorLineEdit::onSelectionChanged()
    {
        lastSelectionStart = selectionStart();
        lastSelectedTextSize = selectedText().size();
    }
    
    void ColorLineEdit::onTextEdited(const QString &text)
    {
        if (!lastSelectedTextSize) {
            // We don't have a selection, so it's either
            // an insertion or deletion, but not both.
            int delta = text.size() - lastTextSize;
            if (delta > 0) {
                // User has inserted text.
                int pos = cursorPosition() - delta;
                for (int ii = 0; ii < delta; ii++) {
                    colors.insert(pos, colorForInsertedText);
                }
            } else {
                // User has erased text.
                int pos = cursorPosition();
                colors.erase(colors.begin() + pos, colors.begin() + pos - delta);
            }
        } else {
            // There was a selection, so we have both removed
            // and inserted text.
            int pos = lastSelectionStart;
            int removedCount = lastSelectedTextSize;
            int insertedCount = cursorPosition() - pos;
            colors.erase(colors.begin() + pos, colors.begin() + pos + removedCount);
            for (int ii = 0; ii < insertedCount; ii++) {
                colors.insert(pos, colorForInsertedText);
            }
        }
    
        setCharColors(colors);
    }
    

    Sample usage

    #include "colorlineedit.h"
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        ColorLineEdit lineEdit;
        QList<QColor> colors;
        colors.append(Qt::red);
        colors.append(Qt::red);
        colors.append(Qt::red);
        colors.append(Qt::red);
        lineEdit.setText("abcd");
        lineEdit.setColorForInsertedText(Qt::blue);
        lineEdit.setCharColors(colors);
        lineEdit.show();
    
        return a.exec();
    }
    

    enter image description here

    enter image description here

    :)

相关问题