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
 

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