Daniel
Daniel

Reputation: 3691

How to show selected text different from list text in QComboBox?

I have a QComboBox with a popup list (a QAbstractItemView) showing different items (QStandardItems). Now, I want the item in the list to show a different text than if the item is selected.

Background:

I am creating a word-processor like style chooser where one can choose, say, "1.1 Heading 2" from the list, indicating the numbering and the style name, but when an item is chosen the combobox should only show the style name, say "Heading 2".

I thought the following question was exactly about what I was asking for but apparently an answer was chosen that does not work (apparently even according to the person asking the question): Can a QComboBox display a different value than whats in it's list?

Upvotes: 2

Views: 1367

Answers (2)

scopchanov
scopchanov

Reputation: 8399

Solution

Since QComboBox uses a list view to display the values, probably the "Qt'iest" way to achieve the desired effect, is to use a custom delegate and modify the text within its paint method, using a hash map (QHash) to get the corresponding string.

Example

Here is a simple example I have prepared for you to demonstrate how the proposed solution could be implemented:

Delegate.h this is where the magic is happening

#include <QStyledItemDelegate>
#include <QApplication>

class Delegate : public QStyledItemDelegate
{
    Q_OBJECT
public:
    explicit Delegate(QObject *parent = nullptr) :
        QStyledItemDelegate(parent) {}

    void setHash(const QHash<int, QString> &hash) {
        m_hash = hash;
    }

    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override {
        if (!index.isValid())
            return;

        QStyleOptionViewItem opt = option;

        initStyleOption(&opt, index);

        opt.text = m_hash.value(index.row());

        QApplication::style()->drawControl(QStyle::CE_ItemViewItem, &opt, painter);
    }

private:
    QHash<int, QString> m_hash;
};

MainWindow.h only for demo purposes

#include <QWidget>
#include <QBoxLayout>
#include <QComboBox>
#include <QStandardItemModel>
#include "Delegate.h"

class MainWindow : public QWidget
{
    Q_OBJECT
public:
    MainWindow(QWidget *parent = nullptr)
        : QWidget(parent)
    {
        auto *l = new QVBoxLayout(this);
        auto *cmbBox = new QComboBox(this);
        auto *model = new QStandardItemModel(this);
        auto *delegate = new Delegate(this);
        QHash<int, QString> hash;

        for (int n = 0; n < 5; n++) {
            // For demo purposes I am using "it#" and "item #"
            // Feel free to set those strings to whatever you need
            model->appendRow(new QStandardItem(tr("it%1").arg(QString::number(n))));
            hash.insert(n, tr("item %1").arg(QString::number(n)));
        }

        delegate->setHash(hash);

        cmbBox->setModel(model);
        cmbBox->setItemDelegate(delegate);

        l->addWidget(cmbBox);
        resize(600, 480);
    }
};

Result

The example produces the following result:

enter image description here

Upvotes: 5

Waqar
Waqar

Reputation: 9331

The easiest way to do is to set the ComboBox as editable and then when the current item changes, you change the text to whatever you want. Example:

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QStringList a = {"Red", "Green", "Blue"};
    aModel.setStringList(a);
    ui->comboBox->setModel(&aModel);
    ui->comboBox->setEditable(true);
}

void MainWindow::on_comboBox_currentIndexChanged(const QString &arg1)
{
    if (arg1 == "Green") {
        ui->comboBox->setCurrentText("Green on");
    } else if (arg1 == "Red") {
        ui->comboBox->setCurrentText("Red on");
    }
}

ui->comboBox->setCurrentText("Green on"); will only change the text when the item is selected, when you reopen the combobox, the text will be reverted back to original. This is somewhat similar to my answer here.

Another way to do this would be to inherit the QComboBox class and then reimplement the mousePressEvent to change the model whenever the mouse is pressed, and switch it back after releasing. This will probably be more difficult to get right or may not even work as I have not tried it myself

Upvotes: 2

Related Questions