How to connect two QComboBox so that the second shows only certain items?

67 views Asked by At

I have two QComboBoxes to connect with each other.

In particular, I'd like that if a scaling is made in the first QComboBox, this is not also shown in the second QComboBox and vice versa.

This is my code:

auto lingua_originaleT = new QComboBox();
lingua_originaleT->addItems({"Italiano", "Inglese", "Francese", "Spagnolo", "Portoghese", "Tedesco", "Cinese"});
auto lingua_targetT = new QComboBox();
lingua_targetT->addItems({"Italiano", "Inglese", "Francese", "Spagnolo", "Portoghese", "Tedesco", "Cinese"});

The result should be like this:

The same language should not appear in the second drop-down menu as well.

3

There are 3 answers

2
Nico J. On

Internally, QCombobox uses QStandardItemModel - unless you provided a custom one using setModel().

That means you can do things like:

// Just some setup
auto combo = new QComboBox(this);
combo->addItems({ "Item0", "Item1", "Item2" });

// Here is the interesting bit
auto model = qobject_cast<QStandardItemModel*>(combo->model());
auto item  = model->item(0); // <-- index in the combobox
item->setEnabled(false); // <-- You can't select it anymore

if(combo->currentIndex() == 0) // Choose another one if it's already selected
    combo->setCurrentIndex(1);

// From now, Item 0 will be visible in the dropdown but not selectable by the user.

I leave you find a way to get the 2 boxes disabling each other items (And importantly, enabling them back once if the selection change). This is a matter of listening the index changed signals of each boxes and and updating the other model accordingly.

0
Gretaas On

I solved and the solution works perfectly! Here's how I did it:

lingua_originaleT = new QComboBox();
lingua_targetT = new QComboBox();

    QStringList traduzioneLangList = {"Italiano", "Inglese", "Francese", "Spagnolo", "Portoghese", "Tedesco", "Cinese"};
    lingua_originaleT->clear();
    lingua_originaleT->addItems(traduzioneLangList);
    lingua_originaleT->setCurrentIndex(-1);
    lingua_targetT->clear();
    lingua_targetT->addItems(traduzioneLangList);
    lingua_targetT->setCurrentIndex(-1);

    connect(lingua_originaleT, &QComboBox::currentTextChanged, lingua_targetT, [=](const QString &selection) {
        auto tarLangList = traduzioneLangList;
        lingua_targetT->blockSignals(true);
        tarLangList.removeOne(selection);
        lingua_targetT->clear();
        lingua_targetT->addItems(traduzioneLangList);
        lingua_targetT->blockSignals(false);
    });
    connect(lingua_targetT, &QComboBox::currentTextChanged, lingua_originaleT, [=](const QString &selection) {
        auto tarLangList = traduzioneLangList;
        lingua_originaleT->blockSignals(true);
        tarLangList.removeOne(selection);
        lingua_originaleT->clear();
        lingua_originaleT->addItems(traduzioneLangList);
        lingua_originaleT->blockSignals(false);
    });
    lingua_originaleT->setCurrentIndex(0);

Many thanks to @lifof on reddit!

2
eyllanesc On

One possible solution is to use QSortFilterProxyModel to do the filtering:

#include <QApplication>
#include <QComboBox>
#include <QHBoxLayout>
#include <QSortFilterProxyModel>
#include <QStandardItemModel>
#include <QWidget>

class FilterProxyModel: public QSortFilterProxyModel{
public:
    using QSortFilterProxyModel::QSortFilterProxyModel;
protected:
    bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const{
        if(filterRegExp().isEmpty())
            return true;
        return !QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QWidget widget;
    widget.resize(640, 480);
    widget.show();

    QStandardItemModel *model = new QStandardItemModel(&widget);
    const QStringList values{"Italiano", "Inglese", "Francese", "Spagnolo", "Portoghese", "Tedesco", "Cinese"};
    for(const QString & value: values){
        model->appendRow(new QStandardItem(value));
    }
    QComboBox *lingua_originaleT = new QComboBox;
    FilterProxyModel *proxy_originalT = new FilterProxyModel(&widget);
    proxy_originalT->setSourceModel(model);
    lingua_originaleT->setModel(proxy_originalT);

    QComboBox *lingua_targetT = new QComboBox;
    FilterProxyModel *proxy_targetT = new FilterProxyModel(&widget);
    proxy_targetT->setSourceModel(model);
    lingua_targetT->setModel(proxy_targetT);

    QHBoxLayout *lay = new QHBoxLayout(&widget);
    lay->addWidget(lingua_originaleT);
    lay->addWidget(lingua_targetT);

    QObject::connect(lingua_originaleT, &QComboBox::currentTextChanged, proxy_targetT, &FilterProxyModel::setFilterFixedString);
    QObject::connect(lingua_targetT, &QComboBox::currentTextChanged, proxy_originalT, &FilterProxyModel::setFilterFixedString);

    lingua_originaleT->setCurrentIndex(0);
    lingua_targetT->setCurrentIndex(1);

    return a.exec();
}