Question

I have a QTreeWidget in which each of its items has a QComboBox in a column. I have connected it to a slot with a QSignalMapper, and I'm successfully retrieving both the item and the index in the combobox when it is triggered. I did it like this:

foreach(Workplace *wp, allWorkplaces){
        QTreeWidgetItem *workplaceItem = new QTreeWidgetItem;

        workplaceItem->setText(0, wp->workplaceName());
        workplaceItem->setText(1, wp->workplaceDescription());

        myWorkplaceUi->treeWidget->addTopLevelItem(workplaceItem);

        QComboBox *combo = new QComboBox();

        combo->addItems(allShiftModels);

        combo->setAutoFillBackground(true);

        ShiftModel *shiftModel = qobject_cast<ShiftModel *>(wp->usedShiftModel);

        myWorkplaceUi->treeWidget->setItemWidget(workplaceItem,2, combo);

        if(shiftModel && !shiftModel->shiftModelName().isEmpty()){
            qDebug()<<"after the cast: "<< shiftModel->shiftModelName();
            combo->setCurrentIndex(combo->findText(shiftModel->shiftModelName(), Qt::MatchExactly));
        }else{
            combo->setCurrentIndex(combo->findText("None", Qt::MatchExactly));
        }

        connect(combo, SIGNAL(currentIndexChanged(int)), signalMapper, SLOT(map()));
        signalMapper->setMapping(combo, QString("%1").arg(wp->workplaceName()));
    }

    connect(signalMapper, SIGNAL(mapped(const QString &)),this, SLOT(changed(const QString &)));

My objective is, after retrieving both the Workplace and the ShiftModel, to update them in the instances of my already created Workplaces. So, basically, I try to find the Workplace and the ShiftModel that were selected, because depending on the ShiftModel selected, I will change a pointer to the ShiftModel in the Workplace class:

class Workplace : public QObject
{
    Q_OBJECT

public:
    (...)
    ShiftModel *usedShiftModel;
    (...)
}

And the changed slot:

void workplacesdialog::changed(QString position){

    QList<Workplace* > allWorkplaces = this->myProject->listMyWorkplaces();
    QList<ShiftModel*> allShiftModels = this->myProject->myFactory->listShiftModels();

    foreach(Workplace* workplace, allWorkplaces){
        foreach(ShiftModel *shiftmodel, allShiftModels){
            qDebug() <<"workplace:"<< workplace->workplaceName();
            qDebug() <<"shiftmodel:"<< shiftmodel->shiftModelName();

            QString wp = position;
            QTreeWidgetItem* item=(QTreeWidgetItem*)myWorkplaceUi->treeWidget->findItems(wp,Qt::MatchExactly,0).at(0);
            QComboBox *combo = (QComboBox*)myWorkplaceUi->treeWidget->itemWidget(item,2);
            if(combo && item){
                QString sm = combo->currentText();

                qDebug() << "selected shiftmodel "<< sm << " on workplace "<< wp;

                        if(workplace->workplaceName()==wp && shiftmodel->shiftModelName()==sm){
                            workplace->usedShiftModel = shiftmodel;
                            break;
                        }
                        else{
                            workplace->usedShiftModel = 0;
                            return;
                        }

            }else{
                qDebug() << "cast failed!";
                return;
            }
        }
    }
}

So, my problem with this is, when I click one of the comboboxes, successfully retrieve both the item and index selected, but then, when I try to traverse them with the two foreach loops in the slot, it does not work as I expected. I hoped that every time I clicked on an index in one of the comboboxes, this would be called, and it is. Although, for some reason, the method I'm using to match what the user selected with what was already instatiated doesn't work.

Also, it looks like it only hits both the 1st workplace on the allWorkplaces list as well as the 1st shiftmodel on the ShiftModels list, and this is my problem.

If anyone knows how to fix this or has any ideas to share, please let me know. Thank you.

Was it helpful?

Solution 2

So, In the end I figured out my loops were really messed up... This is working now:

void workplacesdialog::changed(QString position){

    QList<Workplace* > allWorkplaces = this->myProject->listMyWorkplaces();
    QList<ShiftModel*> allShiftModels = this->myProject->myFactory->listShiftModels();

    qDebug() << allWorkplaces.size() << " workplaces";
    qDebug() << allShiftModels.size() << " ShiftModels";

    QString wp = position;
    QString sm;
    QTreeWidgetItem* item=(QTreeWidgetItem*)myWorkplaceUi->treeWidget->findItems(wp,Qt::MatchExactly,0).at(0);
    QComboBox *combo = (QComboBox*)myWorkplaceUi->treeWidget->itemWidget(item,2);
    if(combo && item){
        sm = combo->currentText();
        qDebug() << "selected shiftmodel "<< sm << " on workplace "<< wp;

    }else{
        qDebug() << "cast failed!";
        return;
    }

    foreach(Workplace* workplace, allWorkplaces){
        foreach(ShiftModel *shiftmodel, allShiftModels){
            qDebug() <<"workplace:"<< workplace->workplaceName();
            qDebug() <<"shiftmodel:"<< shiftmodel->shiftModelName();
            if(workplace->workplaceName()==wp && shiftmodel->shiftModelName()==sm){
                qDebug() << "found match!: "<< wp << " >>>>> " << sm;
                workplace->usedShiftModel = shiftmodel;
                return;
            }else if(workplace->workplaceName()==wp && sm=="None"){
                qDebug() << "clear match: "<< wp << " >>>>> " << sm;
                workplace->usedShiftModel = 0;
                return;
            }
        }
    }
}

OTHER TIPS

The problem is this:

if(workplace->workplaceName()==wp && shiftmodel->shiftModelName()==sm){
    workplace->usedShiftModel = shiftmodel;
    break;
}
else{
    workplace->usedShiftModel = 0;
    return;
}

If either the workplace name does not match, or the shift model name does not match, the relation between the work place and its currently linked shift model is removed and your function returns.

I could restructure the two for-loops for you, but there is an easier and less error-prone way:

Note: I marked some code paths with "TODO" which I skipped due to lack of time. You should be able to figure them out yourself though.

// Set up hashes for quick lookup
QHash< QString, Workplace* > workplaceHash;

QList<Workplace* > allWorkplaces = this->myProject->listMyWorkplaces();
foreach( Workplace* workplace, allWorkplaces )
{
    workplaceHash.insert( workplace, workplace->workplaceName() );
}

// TODO: Do a similar thing for the shift models here

// Find the selected workplace
if( !workplaceHash.contains( position ) )
{
    // TODO: Error handling (An unknown/No workplace was selected)
    return;
}
// else: A valid workplace was selected

Workplace* selectedWorkplace = workplaceHash.value( position );

// TODO: Retrieve the name of the shift model (stored in variable sm)

// Find the selected shiftmodel
if( !shiftplaceHash.contains( sm ) )
{
    // No shift model was selected
    selectedWorkplace->usedShiftModel= 0;
    return;
}
// Else: Both work place and shift model were selected

Shiftplace* selectedShiftModel = shiftplaceHash.value( sm );

selectedWorkplace->usedShiftModel = selectedShiftModel;

A few ideas for refactoring:

  • You could maybe do the creation of the hashes outside of this method and store them in member variables. Just make sure that the hash is always updated when a workplace is added or removed.
  • You could make spotting errors easier by extracting parts of the code into separate methods, e.g. QString getSelectedShiftModelName() etc.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top