0

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.

rgettman
  • 176,041
  • 30
  • 275
  • 357
Gretaas
  • 31
  • 5

3 Answers3

1

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();
}
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
0

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.

Nico J.
  • 167
  • 2
  • 10
  • Your solution just makes it unselectable since the item is disabled but it will still be visible and that's not what the OP wants: *The same language should not appear in the second drop-down menu as well* – eyllanesc Sep 02 '21 at 17:09
  • This is true. though from ux point of view it's easier to relate the two lists with the same shape, same size, same items in the same place. The item not being here means it's unavailable as a target language. the item being disable means it is available but just invalid due to prior origin language selection. But yeah you can argue I'm not answering the question. – Nico J. Sep 02 '21 at 17:13
0

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!

Gretaas
  • 31
  • 5