Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QStandardItem - checkbox - how to capture user change state?



  • Hey

    I want to adjust what is happening when user click on checkbox on qstandarditem. I think its somehwere in mouseRelease event that it has to check if item.checkbox().contains(mouse->pos())(what I imagint it could look like) - but I can't find it in the source. Does any1 know where that check is being made?

    Or maybe there is a better way to adjust the check signal to be sent to all selected items rather than just one? I want to bundle it up into a command to store undo data + change all selected items checkState if they contain that flag...

    Thanks!



  • @Dariusz
    You certainly do not want to approach this by tracking mouse position over checkbox in a mouse release event, and changing Qt source code!


  • Lifetime Qt Champion

    Hi,

    What kind of action should happen when you check/uncheck your item ?



  • @SGaist He said:

    Or maybe there is a better way to adjust the check signal to be sent to all selected items rather than just one?


  • Lifetime Qt Champion

    @JNBarchan I know, but that's doesn't tell what is supposed to happen.

    What are the selected item ?
    How are they supposed to stay selected if there's a checkbox in an item that is clicked ?
    etc.



  • Well currently what I did is

    testITem::mouseReleaseEvent(QMosueEvent *event){
    QModelIndexList selectedLIst = selectedIndexes()
    QModelIndex clickedIndex = indexAt(event->pos())
    QVariant oldItemState;
    // code here that checks the current item state
    
    QTreeView::mouseReleaseEvent(event)
    
    //code here that checks the "new" current item state and compares to oldItemState, if its different then it passes in loop below to selected items... 
    loop over my selectedList{} and set their state to new state.
    }
    

    I coded to check what was clicked and if the QCheckStateRole has changed of clicked item, then I loop over my indexes and do the same. Its a hax and I have 2 undo commands as 1 for clicked item and second for my list. I don't really like it but its the only way I could think of doing it. I think I'll try adjusting it so that my undo command - which now happens in model() - setData function will have a detection maybe to not generate undo command for checkbox and I'll handle that from treeClass or maybe move all to model not sure... its tricky.

    @SGaist said in QStandardItem - checkbox - how to capture user change state?:

    @JNBarchan I know, but that's doesn't tell what is supposed to happen.

    What are the selected item ?
    How are they supposed to stay selected if there's a checkbox in an item that is clicked ?
    etc.

    I select 10 rows, and I click on checkbox in 1 of row, column 0. Then all selected rows, in column 0 should set their checkboxes to the one I clicked initially.

    This is the result of my current "work around" not very proud of it tho... https://imgur.com/a/llOES

    Edit. I just gave another look in to it, It Perhaps I found it, I previously looked in to qstandarditems and qabstractitemmodel/qabstractivemview etc but I didnt look in to tree view... looks like its the decoration > https://code.woboq.org/qt5/qtbase/src/widgets/itemviews/qtreeview.cpp.html#_ZN9QTreeView17mouseReleaseEventEP11QMouseEvent

    Perhaps I can subclass that function - use source base and insert my loop there humhhhhhhh.....

    to be precise:

    if (d->itemDecorationAt(event->pos()) == -1) {
    1901	        QAbstractItemView::mouseReleaseEvent(event);
                            getEvent signal/role/value -> apply to all selectedIndexes....humhhhhh how to get role/signal out of event :D
    
    

    Nope, the last idea looks to be a bit of a headache to implement... I would have to reimplement half of source code :/

    Need to reimplement itemDecorationAt() then itemDecorationRect() whhhh


  • Lifetime Qt Champion

    Shouldn't you rather have a contextual menu with an entry like "Mark selected rows as check" or something like that ?

    For me it would be counterintuitive that clicking on something in a table doesn't clear the current selection. It would also allow you to more cleanly handle undo/redo.



  • @SGaist said in QStandardItem - checkbox - how to capture user change state?:

    Shouldn't you rather have a contextual menu with an entry like "Mark selected rows as check" or something like that ?

    For me it would be counterintuitive that clicking on something in a table doesn't clear the current selection. It would also allow you to more cleanly handle undo/redo.

    I find it more natural in my environment to have multiSelection checkbox update. I use few other apps and they all seems to have similar system implemented. Its just faster/easier. I'll see if I can fine tune my undo system to capture undo of checkboxes in that 1 location. Ahh hate it. I wanted to get all undo commands for treeView in 1 function, duh. Will come back to this issue when I have a "light bulp" :- )

    Uh the table clear selection if you click on anything else but the checkbox.



  • @Dariusz
    Even if you want to do this, I still don't get why you are choosing to approach it with such low-level stuff as mouse events and event position. I would handle the clicked signal on the clicked row, and then something like setCheckState() on whatever other rows you also want?



  • define a signal Q_SIGNAL void checkChanged(const QModelIndex&);

    Then use an additional role to store the previous value of Qt::CheckStateRole and compare it

    enum {ChStateChangedCheck = Qt::UserRole + Qt::CheckStateRole};
    connect(model,&QAbstractItemModel::dataChanged,[=](const QModelIndex& topLeft, const QModelIndex& bottomRight)->void{
    if(!topLeft.isValid()) return;
    Q_ASSERT(topLeft.model() == model);
    if(bottomRight.isValid()){
    Q_ASSERT(bottomRight.model() == model);
    const auto parIdx = topLeft.parent();
    Q_ASSERT(parIdx  == bottomRight.parent());
    for(int i=topLeft.row();i<=bottomRight.row();++i){
    for(int j=topLeft.column();j<=bottomRight.column();++j){
    const auto currIdx = model->data(i,j,parIdx);
    if(currIdx.data(ChStateChangedCheck) != currIdx.data(Qt::CheckStateRole)){
    model->setData(currIdx,currIdx.data(Qt::CheckStateRole),ChStateChangedCheck);
    emit checkChanged(currIdx);
    }
    }
    }
    else{
    if(topLeft.data(ChStateChangedCheck) != topLeft.data(Qt::CheckStateRole)){
    model->setData(topLeft,topLeft.data(Qt::CheckStateRole),ChStateChangedCheck);
    emit checkChanged(topLeft);
    }
    }
    }
    

    P.S. Could you please vote for this bug: https://bugreports.qt.io/browse/QTBUG-63766 as it's solution would transform your problem into just checking the 3rd argument of the dataChanged signal


Log in to reply