Qt delegate display text rendered while editor is active
<p>I implemented a unit text box capable of doing conversions when a different unit is selected. This was done by sticking a QLineEdit and QLabel together using a QHBoxLayout.</p>

<p><a href="https://i.stack.imgur.com/DoWeS.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/DoWeS.png" alt="enter image description here"></a></p>

<pre><code>class LengthTextBox::Impl
{
    public:
        Impl() :
            lblUnit(new QLabel()),
            txtValue(new QLineEdit()),
            menuLength(new LengthMenu(lblUnit)),
            precision(2),
            unit(units::Length::Meters)
        {
        }

        QLabel* lblUnit;
        QLineEdit* txtValue;
        LengthMenu* menuLength;

        int precision;

        units::Length unit;
};

LengthTextBox::LengthTextBox(QWidget* parent) : QWidget(parent),
    pimpl()
{
    const auto hLayout = new QHBoxLayout(this);

    // Adjust spacing for better fit within tables.
    const auto spacing = 2;
    auto margins = hLayout-&gt;contentsMargins();
    margins.setTop(0);
    margins.setLeft(spacing);
    margins.setRight(spacing);
    margins.setBottom(0);
    hLayout-&gt;setContentsMargins(margins);
    hLayout-&gt;setSpacing(spacing);

    this-&gt;pimpl-&gt;txtValue-&gt;setValidator(new QDoubleValidator());

    // Install an event filter to capture focus out events.
    this-&gt;pimpl-&gt;txtValue-&gt;installEventFilter(this);

    hLayout-&gt;addWidget(this-&gt;pimpl-&gt;txtValue);
    hLayout-&gt;addWidget(this-&gt;pimpl-&gt;lblUnit);

    // Since we're building on top of a QWidget, set up the focus policies to still focus on the text box.
    this-&gt;setFocusProxy(this-&gt;pimpl-&gt;txtValue);
    this-&gt;pimpl-&gt;txtValue-&gt;setFocusPolicy(Qt::StrongFocus);
    this-&gt;pimpl-&gt;lblUnit-&gt;setFocusPolicy(Qt::ClickFocus);

    // Connect signals for switching between units.
    this-&gt;connect(this-&gt;pimpl-&gt;lblUnit, &amp;QLabel::linkActivated, this, &amp;LengthTextBox::unitSelectorClicked);
    this-&gt;connect(this-&gt;pimpl-&gt;menuLength, &amp;LengthMenu::unitChanged, this, &amp;LengthTextBox::setUnit);

    // Forward the line edit signals.
    this-&gt;connect(this-&gt;pimpl-&gt;txtValue, &amp;QLineEdit::editingFinished, this, &amp;LengthTextBox::editingFinished);
    this-&gt;connect(this-&gt;pimpl-&gt;txtValue, &amp;QLineEdit::returnPressed, this, &amp;LengthTextBox::returnPressed);
    this-&gt;connect(this-&gt;pimpl-&gt;txtValue, &amp;QLineEdit::textChanged, this, &amp;LengthTextBox::textChanged);
    this-&gt;connect(this-&gt;pimpl-&gt;txtValue, &amp;QLineEdit::textEdited, this, &amp;LengthTextBox::textEdited);

    this-&gt;setUnit(this-&gt;pimpl-&gt;unit);
}

LengthTextBox::~LengthTextBox()
{
}

void LengthTextBox::setPrecision(int x)
{
    this-&gt;pimpl-&gt;precision = x;
}

int LengthTextBox::getPrecision() const
{
    return this-&gt;pimpl-&gt;precision;
}

void LengthTextBox::setUnit(const units::Length&amp; x)
{
    const auto value = this-&gt;getValue();
    this-&gt;setValue(units::Convert(value, this-&gt;pimpl-&gt;unit, x));

    // Use HTML to render the text as a link. This will lead to the linkActivated signal when clicked.
    const QString link = "&lt;b&gt;&lt;a href='#'&gt;" + QString::fromStdString(units::GetSymbol(x)) + "&lt;/a&gt;&lt;/b&gt;";
    this-&gt;pimpl-&gt;lblUnit-&gt;setText(link);

    this-&gt;pimpl-&gt;txtValue-&gt;setFocus(Qt::FocusReason::OtherFocusReason);
    this-&gt;pimpl-&gt;txtValue-&gt;selectAll();

    this-&gt;pimpl-&gt;unit = x;
    this-&gt;unitChanged(this-&gt;pimpl-&gt;unit);
}

units::Length LengthTextBox::getUnit() const
{
    return this-&gt;pimpl-&gt;unit;
}

void LengthTextBox::setValue(double x, const units::Length&amp; fromUnit)
{
    if(fromUnit != units::Length::Unknown)
    {
        x = units::Convert(x, fromUnit, this-&gt;pimpl-&gt;unit);
    }

    this-&gt;pimpl-&gt;txtValue-&gt;setText(QString::number(x, 'f', this-&gt;pimpl-&gt;precision));
}

double LengthTextBox::getValue(const units::Length&amp; toUnit) const
{
    auto value = this-&gt;pimpl-&gt;txtValue-&gt;text().toDouble();

    if(toUnit != units::Length::Unknown)
    {
        value = units::Convert(value, this-&gt;pimpl-&gt;unit, toUnit);
    }

    return value;
}

std::string LengthTextBox::getFormattedText() const
{
    return this-&gt;pimpl-&gt;txtValue-&gt;text().toStdString() + " " + units::GetSymbol(this-&gt;pimpl-&gt;unit);
}

void LengthTextBox::unitSelectorClicked()
{
    this-&gt;pimpl-&gt;menuLength-&gt;popup(QCursor::pos());
}

bool LengthTextBox::eventFilter(QObject* obj, QEvent* x)
{
    // Watch for a focus out event on the text box inorder to send a lost focus signal.
    if(this-&gt;pimpl-&gt;txtValue == obj)
    {
        if(x-&gt;type() == QEvent::FocusOut &amp;&amp; this-&gt;pimpl-&gt;lblUnit-&gt;hasFocus() == false)
        {
            this-&gt;lostFocus();
            return true;
        }
    }

    return QWidget::eventFilter(obj, x);
}
</code></pre>

<p>Next, I derived a QStyledItemDelegate so that I could use this text box in my own QTableView.
<a href="https://i.stack.imgur.com/BTX4v.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/BTX4v.png" alt="enter image description here"></a></p>

<p>If you looks very closely, you'll see that when the editor is active on this delegate, that the letter 'm' is rendered behind the hyperlink 'm'.</p>

<pre><code>class LengthTextBoxDelegate::Impl
{
    public:
        Impl(int precision) :
            txtLength(std::make_unique&lt;LengthTextBox&gt;())
        {
            this-&gt;txtLength-&gt;setPrecision(precision);
        }

        // By using a length text box to manage current selected unit, all conversion logic remains in one place.
        std::unique_ptr&lt;LengthTextBox&gt; txtLength;
};

LengthTextBoxDelegate::LengthTextBoxDelegate(int precision, QWidget* parent) : QStyledItemDelegate(parent),
    pimpl(precision)
{
}

LengthTextBoxDelegate::~LengthTextBoxDelegate()
{
}

QString LengthTextBoxDelegate::displayText(const QVariant&amp; value, const QLocale&amp;) const
{
    this-&gt;pimpl-&gt;txtLength-&gt;setValue(value.toDouble(), Length::Meters);
    return QString::fromStdString(this-&gt;pimpl-&gt;txtLength-&gt;getText()) + " " + QString::fromStdString(GetSymbol(this-&gt;pimpl-&gt;txtLength-&gt;getSelectedUnit()));
}

QWidget* LengthTextBoxDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem&amp;, const QModelIndex&amp; index) const
{
    const auto txtLength = new LengthTextBox(parent);
    txtLength-&gt;setValue(index.data().toDouble());
    txtLength-&gt;setSelectedUnit(this-&gt;pimpl-&gt;txtLength-&gt;getSelectedUnit());
    txtLength-&gt;setPrecision(this-&gt;pimpl-&gt;txtLength-&gt;getPrecision());

    // AMS // This is kind of a hack. For some reason, the ::displayText() that is rendered when no editor is created, was getting rendered
    // behind the editor widget and was appearing through as if the text box was transparent.
    // By setting the background color white, we get a nice aesthetic that matches the table views that use this delegate.
    // In addition, it covers up the text that was appearing behind the widget.
    auto p = txtLength-&gt;palette();
    p.setColor(QPalette::Base, Qt::white);
    txtLength-&gt;setPalette(p);
    //txtLength-&gt;setAutoFillBackground(true);

    // Track the current unit so that its symbol can be rendered when ::displayText() is called.
    this-&gt;connect(txtLength, &amp;LengthTextBox::unitChanged, this, &amp;LengthTextBoxDelegate::unitChanged);
    this-&gt;connect(txtLength, &amp;LengthTextBox::returnPressed, this, &amp;LengthTextBoxDelegate::commitAndCloseEditor);
    this-&gt;connect(txtLength, &amp;LengthTextBox::lostFocus, this, &amp;LengthTextBoxDelegate::commitAndCloseEditor);

    return txtLength;
}

void LengthTextBoxDelegate::setEditorData(QWidget* editor, const QModelIndex&amp; index) const
{
    const auto txtLength = qobject_cast&lt;LengthTextBox*&gt;(editor);
    assert(txtLength != nullptr);

    txtLength-&gt;setValue(index.data().toDouble(), Length::Meters);
}

void LengthTextBoxDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex&amp; index) const
{
    const auto txtLength = qobject_cast&lt;LengthTextBox*&gt;(editor);
    assert(txtLength != nullptr);

    model-&gt;setData(index, txtLength-&gt;getValue(Length::Meters));
}

void LengthTextBoxDelegate::unitChanged(const hive::math::units::Length&amp; x)
{
    this-&gt;pimpl-&gt;txtLength-&gt;setSelectedUnit(x);
}

void LengthTextBoxDelegate::commitAndCloseEditor()
{
    const auto txtLength = qobject_cast&lt;LengthTextBox*&gt;(this-&gt;sender());
    this-&gt;commitData(txtLength);
    this-&gt;closeEditor(txtLength);
}
</code></pre>

<p>So far the only solution I've come up with is to set the background color on my editor widget. This feels hackish, there must be something else I'm doing wrong.</p>

<p><a href="https://i.stack.imgur.com/AOBHp.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/AOBHp.png" alt="enter image description here"></a></p>

<p>Is there a way to prevent the Qt::DisplayRole text from being rendered while my editor is active?</p>