take a widget from a QTableWidget



  • Hi my friends.
    I have populated a QTableWidget with many QWidget's. I do this with setCellWidget.
    I want to move widgets from one row to another, i want to swap rows.
    It is possible to "take" a widget like "takeItem" and "set" it with "setItem" (i would use setCellWidget) ?
    If i simple copy a pointer with "cellWidget()", then in a moment i use "setCellWidget" it will delete this widget.
    Or i simply need to make a copy ?
    Thanks for any answer.
    Daniel


  • Qt Champions 2016

    Hi
    When you use setCellWidget the QTableWidget will own the widget.
    Reading the doc, there doesn't seems to be a way to take back ownership as it seems
    cellWidget() only allows access to it not to take it back so to speak.

    So a way is to create function that can create the widgets as you want and
    simply recreate the widgets when you want to "swap" them as
    you cannot really make a copy as such.

    So you could make a function that takes widget and copy some data
    from it and create new one with those data
    or create a new with default value if widget is not supplied.



  • Thanks for you answer.
    I already read all docs , and i know that its not possible to take back ownership, ...
    but you idea of recreate the widgets is very good, and its possible to do.
    At this time, i am already trying another approach :

    m_tagsTable->verticalHeader()->moveSection(row,rowsel);
    

    i also catch this moving section action with :

    connect(m_tagsTable->verticalHeader(),SIGNAL(sectionMoved(int,int,int)),SLOT(tagsTableVerticalSectionMoved(int,int,int)));
    

    And on place in which i catch this ... i change just this verticalHeader()... :

    QTableWidgetItem* item1 = new QTableWidgetItem(QString::number(newVisualIndex+1)+"j");
    m_tagsTable->setVerticalHeaderItem(newVisualIndex,item1);
    

    but what now is very strange its, that newVisualIndex its not true. I mean he always give a number which is the first number which has at beginning, but not the actual row. My slot is :

    void TagExtSearchDlg::tagsTableVerticalSectionMoved(int, int oldVisualIndex, int newVisualIndex)
    

    and its same as in
    http://doc.qt.io/qt-4.8/qheaderview.html#sectionMoved
    so, this third argument is "newVisualIndex", but it give me like a not changing logicalIndex
    So for example if at begin, it write in all rows of vertical header in succession : 1,2,3,4
    After doing a drag drop from first row to second row, all is moving right but, it write at vertical header : 2, 1j, 3, 4
    And result must be : 2, 2j, 3, 4
    (of course i would write also in first row)
    I put a "j" for a signal to know which header have changed my code, after a drag and drop.
    Thanks for any more help.
    Daniel


  • Qt Champions 2016

    Hi
    Good to hear that recreate is possible if section move fails.
    Also good idea as that is truly a column swap.

    I agree that I would expect new visual index be 2 also
    when moved.
    Could you check with
    int QHeaderView::visualIndex(int logicalIndex) const
    to see if its the SectionMoved that reports unexpected value or
    if it really mean it.



  • Hi
    Its a row swap.
    But i slowly encounter which problems arise using a moving section.
    Problem its i react inside "cellEntered", and from this slot i do a "moveSection".
    Problem its, that it makes recursive (until a 10 times may be), because moving a section also cause a new "cellEntered" activation.
    At next i will try you approach, which i am sure not will be a problem.
    Ok, not it will be easy at all, because i need to adjust may conexions of subbuttons from swapped rows.
    Now i need to sleep, but i can give you all code of a part which actualize all rows :

    void TagExtSearchDlg::actualizeTagsTable(bool useAtagsList)
    {
        if (!useAtagsList) actualizeAtagsList();//useAtagsList mean we not actualize AtagsList
        setDefaultRelationTypes();
        //m_tagsTable->clear();
    
        m_tagsTable->setRowCount(m_atagsList.size());
           //m_tagManager.actualizeAtagToIndex();//deprecated
        int* defaults[4] = { &typeDefaultSubset,&typeDefaultSSubset,&typeDefaultEquiv,&typeDefaultOther};
        int col[4] = { 1,2,3,4};
        const TagExtManager& tagManager = m_tagManager;
        for(int row=0;row<m_atagsList.size();row++) {
            int atag = m_atagsList.at(row);
            const TagExt& tag = tagManager.getTagQ(atag);
            QTableWidgetItem* item = new QTableWidgetItem(tag.m_name);
            item->setData(Qt::UserRole,QVariant(atag));
            m_tagsTable->setItem(row,0,item);
    //        QTableWidgetItem* hitem = new QTableWidgetItem(QString::number(row+1));
    //        hitem->setData(Qt::UserRole,QVariant(atag));
    //        m_tagsTable->setVerticalHeaderItem(row,hitem);
        }
        m_buttonHash.clear();
        QSignalMapper* signalMapper1 = new QSignalMapper(this);
        QSignalMapper* signalMapper2 = new QSignalMapper(this);
        QSignalMapper* signalMapper3 = new QSignalMapper(this);
        typedef RelationClass RC;
        RelationClass classes[4] = { RC::partialOrder(), RC::strictPartialOrder(),
                                    RC::equivalenceRelation(), RC::directedGraph() };
        m_tagManager.actualizeRelationsInv();
        for(int t=0;t<4;t++) {
            if ((*defaults[t])==0) continue;
            m_tagManager.actualizeSpecRelations(*defaults[t]);
            m_tagManager.actualizeSpecRelationsInv(*defaults[t]);
            QList<int> arels;
            if (t<3) arels = m_relManager.getRelationTypeArels(classes[t]);
            else arels = m_relManager.getRelationTypeArels();
            QSet<int> arelsS;
            for(int t=0;t<arels.size();t++) arelsS.insert(arels[t]);
            if (t<3) arelsS.remove(*defaults[t]);
            else { for(int tt=0;tt<3;tt++) arelsS.remove(*defaults[t]); }
            QString relName = m_relManager.getRelationTypeName(*defaults[t]);
            for(int row=0;row<m_atagsList.size();row++) {
                int atag = m_atagsList.at(row);
                const TagExt& tag = tagManager.getTagQ(atag);
                QPair<int,int> rowCol(row,t+1);
                //QTableWidgetItem* item2 = new QTableWidgetItem()
                int sizeUp = tag.m_specRelations.size();
                int sizeDown = tag.m_specRelationsInv.size();
                bool haveUp = sizeUp>0;
                bool haveMore = false;
                QSet<int> tagArelsS;
                for(int r=0;r<tag.m_relations.size();r++) tagArelsS.insert(tag.m_relations.at(r).arel);
                for(int r=0;r<tag.m_relationsInv.size();r++) tagArelsS.insert(tag.m_relationsInv.at(r).arel);
                for(int arel : tagArelsS) if (arelsS.contains(arel)) { haveMore=true; break;}
                bool haveDown = sizeDown>0;
                QWidget* w=0;
                if (haveUp || haveMore || haveDown) { //will have same botton
                    QGroupBox* box = new QGroupBox();
                    QHBoxLayout* lay = new QHBoxLayout;
                    if (haveUp) {
                        QPushButton* but1 = new QPushButton("\u25b2");
                        but1->setToolTip(relName);
    
                        lay->addWidget(but1);
                        m_buttonHash.insert(but1,rowCol);
                        connect(but1,SIGNAL(clicked()),signalMapper1,SLOT(map()));
                        signalMapper1->setMapping(but1, qobject_cast<QWidget*>(but1));
                    }
                    if (haveMore) {
                        QPushButton* but2 = new QPushButton("\u2026");
                        lay->addWidget(but2);
                        m_buttonHash.insert(but2,rowCol);
                        connect(but2,SIGNAL(clicked()),signalMapper2,SLOT(map()));
                        signalMapper2->setMapping(but2, qobject_cast<QWidget*>(but2));
                    }
                    if (haveDown) {
                        QPushButton* but3 = new QPushButton("\u25bc");
                        but3->setToolTip(relName);
                        lay->addWidget(but3);
                        m_buttonHash.insert(but3,rowCol);
                        connect(but3,SIGNAL(clicked()),signalMapper3,SLOT(map()));
                        signalMapper3->setMapping(but3, qobject_cast<QWidget*>(but3));
                    }
                    box->setLayout(lay);
                    //box->setFlat(true);
                    box->setStyleSheet("border:0;");
    
                    w = box;
    
                }
                m_tagsTable->setCellWidget(row,col[t],w);
            }
        }
        connect(signalMapper1, SIGNAL(mapped(QWidget*)),this, SLOT(butUpClicked(QWidget*)));
        connect(signalMapper2, SIGNAL(mapped(QWidget*)),this, SLOT(butMoreClicked(QWidget*)));
        connect(signalMapper3, SIGNAL(mapped(QWidget*)),this, SLOT(butDownClicked(QWidget*)));
    }
    


  • Hi,
    i already have managed it, to actualize (rewrite) 2 rows. And it works as expected.
    In order to reuse code, last sended function reduce to less as 50 lines, and then is better, however use 2 subrutines.
    Thanks for your help.
    In case somebody also want to know how drag and drop rows from a QTableWidget with QWidgets, i send here my code :
    I use cellClicked - signal for know a begginning place for a drag-and-drop :

    void TagExtSearchDlg::tagsTableCellPressed(int row, int)
    {
        m_clickedRow = row;
    }
    

    In order to know a destination row of a drag and drop action i use signal "cellEntered". My slot is :

    void TagExtSearchDlg::tagsTableCellEntered(int row, int)
    {
        int row2;
        if(m_clickedRow<row) row2=row-1; //down
        else if(m_clickedRow>row) row2=row+1; //up
        else return;
        if (m_orderStyleCombo->currentData().toInt()!=byCustom) return;
        //m_tagsTable->verticalHeader()->moveSection(rowsel,row);
        m_clickedRow = row;
        //swap rows inside m_atagsList
        if (m_atagsList.size()<=std::max(row2,row)) return;
        int tempAtag = m_atagsList.at(row);
        m_atagsList[row] = m_atagsList[row2];
        m_atagsList[row2] = tempAtag;
        actualizeTagsTableRows(QList<int>()<<row2<<row);
    }
    

    I also send all code used for actualize rows :

    void TagExtSearchDlg::actualizeTagsTableRows(QList<int> rows)
    {
        int* defaults[4] = { &typeDefaultSubset,&typeDefaultSSubset,&typeDefaultEquiv,&typeDefaultOther};
        const TagExtManager& tagManager = m_tagManager;
        for(int row : rows) {
            int atag = m_atagsList.at(row);
            const TagExt& tag = tagManager.getTagQ(atag);
            QTableWidgetItem* item = new QTableWidgetItem(tag.m_name);
            item->setData(Qt::UserRole,QVariant(atag));
            m_tagsTable->setItem(row,0,item);
        }
        typedef RelationClass RC;
        RelationClass classes[4] = { RC::partialOrder(), RC::strictPartialOrder(),
                                    RC::equivalenceRelation(), RC::directedGraph() };
        m_tagManager.actualizeRelationsInv();
        for(int t=0;t<4;t++) {
            int defaultType = (*defaults[t]);
            if (defaultType==0) continue;
            m_tagManager.actualizeSpecRelations(defaultType);
            m_tagManager.actualizeSpecRelationsInv(defaultType);
            QSet<int> arelsS;
            actualizeTagsTableGetArelsS(arelsS,t==3,defaultType,classes[t]);
            QString relName = m_relManager.getRelationTypeName(defaultType);
            for(int row : rows) {
                int atag = m_atagsList.at(row);
                const TagExt& tag = tagManager.getTagQ(atag);
                actualizeTagsTableSubbuttons(tag,row,t+1,arelsS,relName);
            }
        }
    }
    
    void TagExtSearchDlg::actualizeTagsTableGetArelsS(QSet<int> &arelsS, bool isMoreCol, int defaultType, const RelationClass &cl)
    {
        QList<int> arels;
        if (!isMoreCol) arels = m_relManager.getRelationTypeArels(cl);
        else arels = m_relManager.getRelationTypeArels();
        arelsS.clear();
        for(int t=0;t<arels.size();t++) arelsS.insert(arels[t]);
        if (!isMoreCol) arelsS.remove(defaultType);
        else { for(int tt=0;tt<3;tt++) arelsS.remove(defaultType); }
    }
    
    void TagExtSearchDlg::actualizeTagsTableSubbuttons(const TagExt &tag, int row, int col, const QSet<int> &arelsS, QString relName)
    {
        QPair<int,int> rowCol(row,col);
        //QTableWidgetItem* item2 = new QTableWidgetItem()
        int sizeUp = tag.m_specRelations.size();
        int sizeDown = tag.m_specRelationsInv.size();
        bool haveUp = sizeUp>0;
        bool haveMore = false;
        QSet<int> tagArelsS;
        for(int r=0;r<tag.m_relations.size();r++) tagArelsS.insert(tag.m_relations.at(r).arel);
        for(int r=0;r<tag.m_relationsInv.size();r++) tagArelsS.insert(tag.m_relationsInv.at(r).arel);
        for(int arel : tagArelsS) if (arelsS.contains(arel)) { haveMore=true; break;}
        bool haveDown = sizeDown>0;
        QWidget* w=0;
        if (haveUp || haveMore || haveDown) { //will have same botton
            QGroupBox* box = new QGroupBox();
            QHBoxLayout* lay = new QHBoxLayout;
            if (haveUp) {
                QPushButton* but1 = new QPushButton("\u25b2");
                but1->setToolTip(relName);
                lay->addWidget(but1);
                m_buttonHash.insert(but1,rowCol);
                connect(but1,SIGNAL(clicked()),m_signalMapper1,SLOT(map()));
                m_signalMapper1->setMapping(but1, qobject_cast<QWidget*>(but1));
            }
            if (haveMore) {
                QPushButton* but2 = new QPushButton("\u2026");
                lay->addWidget(but2);
                m_buttonHash.insert(but2,rowCol);
                connect(but2,SIGNAL(clicked()),m_signalMapper2,SLOT(map()));
                m_signalMapper2->setMapping(but2, qobject_cast<QWidget*>(but2));
            }
            if (haveDown) {
                QPushButton* but3 = new QPushButton("\u25bc");
                but3->setToolTip(relName);
                lay->addWidget(but3);
                m_buttonHash.insert(but3,rowCol);
                connect(but3,SIGNAL(clicked()),m_signalMapper3,SLOT(map()));
                m_signalMapper3->setMapping(but3, qobject_cast<QWidget*>(but3));
            }
            box->setLayout(lay);
            box->setStyleSheet("border:0;");
            w = box;
    
        }
        m_tagsTable->setCellWidget(row,col,w);
    }
    

  • Qt Champions 2016

    Super.
    I tried yesterday if it was possible to steal the widget back using set Parent but
    looking at the source code , made me realize that no matter what, the QTableWidget
    would call deletelater on the cell widget so we would crash.

    So Its good to see you made recreate work and thank you for sharing your solution.



  • In case, also want to know how look this QTableWidget, i also send a picture :
    https://goo.gl/photos/2dRkAcwTDz4kgXyY9
    QTableWidget which i actualize are at upper left corner.
    greatings, Daniel


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.