Results 1 to 8 of 8

Thread: How to cancel pending signals?

  1. #1
    Join Date
    Dec 2009
    Posts
    49
    Thanks
    3
    Thanked 2 Times in 1 Post
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Question How to cancel pending signals?

    I have a QTreeWidget. When the user selects an item (of type QTreeWidgetItem) and presses the Delete key, a slot is invoked on this item to delete itself.

    Under certain circumstances, deleting an item might take long enough for the user to press Delete a second time on the same item, leading in my case to a crash.

    What is the best way to handle this situation?

    I'm using Qt 4.8.6.
    Last edited by dictoon; 8th October 2015 at 14:17.

  2. #2
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,419
    Thanks
    37
    Thanked 1,546 Times in 1,496 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to cancel pending signals?

    You could take or hide the item instead of deleting it, and then call a deletion function using QMetaObject::invokeMethod() with Qt::QueuedConnection.

    Cheers,
    _

  3. #3
    Join Date
    Dec 2009
    Posts
    49
    Thanks
    3
    Thanked 2 Times in 1 Post
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: How to cancel pending signals?

    Thanks for your answer anda_skoa, but I'm not sure I fully understand.

    Right now, I create a context menu (QMenu) with the QTreeWidget as parent, then add an action to that menu that will delete the selected item(s):

    Qt Code:
    1. QMenu* menu = new QMenu(treeWidget());
    2. ...
    3. menu->addAction("Delete", this, SLOT(slot_delete()), QKeySequence(Qt::Key_Delete));
    4. ...
    5. menu->exec(treeWidget()->mapToGlobal(point));
    To copy to clipboard, switch view to plain text mode 
    And here is a slot_delete():

    Qt Code:
    1. void MyItem::slot_delete()
    2. {
    3. // Do a bunch of stuff here, might take some time.
    4.  
    5. delete this;
    6. }
    To copy to clipboard, switch view to plain text mode 
    How would I change this?

    I'm not sure how first hiding or taking out the item in slot_delete() would fix the problem.
    Last edited by dictoon; 8th October 2015 at 17:42.

  4. #4
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    4,695
    Thanks
    259
    Thanked 753 Times in 743 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: How to cancel pending signals?

    How would I change this?
    If slot_delete() really *is* a slot, then it is impossible for the user to press Delete a second time and have the slot interrupted. All of the processing in a slot is performed and then the function exits and control returns to the event loop.

    What is probably happening in your case is that you aren't clearing whatever data structure you use to keep track of the pointer to the "selected item", so that when the event loop gets around to processing the second Delete signal, the item you are showing as the "selected item" is already gone, and you try to access it through the now invalid pointer. That's what causes your crash.

    So you need to truly clean up everything associated with the item, including places where a pointer to it might be stored *before* leaving your slot.

    In my opinion, though, a user interface design that performs an irreversible action (like deleting something) without giving the user a way to say, "Oops, I didn't mean that!" is not one that will make people happy for very long. An undo stack, a confirmation dialog that asks "Are you sure?", whatever.

  5. The following user says thank you to d_stranz for this useful post:

    dictoon (9th October 2015)

  6. #5
    Join Date
    Dec 2009
    Posts
    49
    Thanks
    3
    Thanked 2 Times in 1 Post
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: How to cancel pending signals?

    Thanks for chiming in d_stranz.

    If slot_delete() really *is* a slot, then it is impossible for the user to press Delete a second time and have the slot interrupted.
    It's not like the slot execution gets interrupted; my impression is rather that Qt queues up further signals for this item, but the item no longer exists after the first slot_delete() invocation.

    I think you're right though, our actual code is slightly different than what I pasted here, and that's likely the cause of our problem:


    EDIT: Now it's clear: we cannot delete items during rendering, so in that case we queue deletion actions. Of course all deletion actions after the first one will operate on an item that no longer exists. Somehow we need to check if the item still exists...

    In my opinion, though, a user interface design that performs an irreversible action (like deleting something) without giving the user a way to say, "Oops, I didn't mean that!" is not one that will make people happy for very long.
    Of course, but this seems like a completely orthogonal issue to what we are discussing here.

    (We'll go for an undo stack.)

  7. #6
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    4,695
    Thanks
    259
    Thanked 753 Times in 743 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: How to cancel pending signals?

    EDIT: Now it's clear: we cannot delete items during rendering, so in that case we queue deletion actions.
    No, you still don't understand - you are deleting the item in your slot, but there are references to the pointer that are stored elsewhere that aren't getting cleaned up before leaving the slot. There is no rendering going on while your slot is executing - it can only happen *after* leaving the slot. There is no need to queue anything or take any other special action other than to ensure that *anything* that is storing a reference to the object you have just deleted is cleaned up prior to leaving the slot.

    Note that this doesn't have to be something in *your* code - if the object you are deleting inherits from QObject, then there could be references you don't know about that Qt maintains. To avoid this, you probably *don't* want to call "delete this" in the slot. Instead, you call "deleteLater()", which will ensure that any references to the object through the QObject system are also cleaned up. The next time the event loop runs, the instance will be cleaned up after, and then will get deleted.

  8. #7
    Join Date
    Dec 2009
    Posts
    49
    Thanks
    3
    Thanked 2 Times in 1 Post
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: How to cancel pending signals?

    Quote Originally Posted by d_stranz View Post
    No, you still don't understand - you are deleting the item in your slot
    Yes, I do understand the problem now (thanks to your heads up in your first post), but maybe I didn't explain well what we're doing wrong:

    This is the UI of a debug/inspection tool for an offline rendering engine. We cannot delete entities from the scene (*our* scene) while our program is rendering. I'm not talking about Qt rendering here, I'm talking about our program doing its computational business (in other threads). So, during rendering, instead of simply deleting an item when the user selects one and presses Delete, we *queue* the deletion action (using *our* queue mechanism). Obviously at this point the item still exists in the UI and is still available to the user, and nothing prevents him from deleting again the same item.

    So, as you hinted, there *are* other references in our system (in the action queue, specifically) to the item that was just deleted. We need to implement a mechanism to either remove conflicting/non-longer-applying actions from the action queue, or to limit the size of the action queue to 1 action, or something else.

    Incidentally, switching to deleteLater() might be a good option, even though 'delete this' never caused any problems.

    Cheers,
    Franz
    Last edited by dictoon; 9th October 2015 at 09:55.

  9. #8
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    4,695
    Thanks
    259
    Thanked 753 Times in 743 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: How to cancel pending signals?

    OK, that's a little more clear. I found use of deleteLater() was required when I was removing items from a tree view (if I remember correctly). Simply calling delete would result in a crash, presumably due to dangling references.

    I have used the QObject::destroyed() signal successfully as part of a cleanup mechanism. As the docs say, it is emitted immediately before the instance is deleted, so you can still use the pointer if needed.

Similar Threads

  1. Replies: 6
    Last Post: 18th January 2012, 21:21
  2. Replies: 5
    Last Post: 16th September 2010, 20:45
  3. Pending network replies won't let program to quit
    By novichkov in forum Qt Programming
    Replies: 0
    Last Post: 4th August 2010, 20:28
  4. Cancelling a pending database insert
    By innerhippy in forum Qt Programming
    Replies: 3
    Last Post: 30th October 2008, 09:53
  5. closing file objects of pending requests in QHttp
    By nisha0609 in forum Qt Programming
    Replies: 1
    Last Post: 18th January 2007, 11:52

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.