Results 1 to 4 of 4

Thread: Prevent signals from "stacking up"?

  1. #1
    Join Date
    Nov 2011
    Posts
    4
    Thanks
    2
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Prevent signals from "stacking up"?

    Hello Qt Centre,

    I have an application that is split into two parts: the GUI, and a Manager object. Manager is a QObject with several slots, and when the slots are invoked, they run in a separate thread. QObject::moveToThread() makes this very easy.

    Buttons on the GUI are connected to slots on the Manager. The Manager controls a piece of hardware (I don't think the specifics here are too important - what is important is the slots do not execute instantaneously).

    The essence of my problem is that my users have a tendency to mash the buttons faster than the slots can execute (faster than the hardware's motors can move), causing the Manager object to repeatedly invoke a slot. This is rarely what the users want, and ultimately they have to wait for the hardware to finish performing all their unwanted actions before they can start being productive again.

    OK, so the solution is simple, right? Just tell the users to not do that, problem solved! If only it were that easy

    My solution up until this point has been for the Manager object to emit a "I am busy" signal to the GUI. A slot on the GUI loops through most of the widgets in the GUI and disables them. Then when the Manager is done executing, it emits a signal indicating that it is not busy anymore, and the GUI turns all the widgets back on. This approach has worked for a while, but it is starting to be a bit of a maintenance burden: certain widgets need to be disabled for other reasons (hardware has entered a state where certain functionality is unavailable). The code for widget enabling/disabling is starting to smell bad. I am now in search of a cleaner solution to the button mashing problem.


    Ideally, if a slot on the Manager is currently executing, additional signals connected to the slot will be ignored, or perhaps two or three signals would be queued, and subsequent signals discarded until the slot is done executing.

    I've done a bit of searching but I have not been able to articulate my problem very well to Google (I hope I have done an OK job of describing it here...)

    Qt::BlockingQueuedConnection does not do what I need.

    Have I just designed my application badly?
    Is there a name for a design pattern that I can try to understand, that either does not have this problem, or solves it elegantly?
    Any insight or guidance would be greatly appreciated.

    Thanks in advance

  2. #2
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Prevent signals from "stacking up"?

    Quote Originally Posted by jms View Post
    My solution up until this point has been for the Manager object to emit a "I am busy" signal to the GUI. A slot on the GUI loops through most of the widgets in the GUI and disables them. Then when the Manager is done executing, it emits a signal indicating that it is not busy anymore, and the GUI turns all the widgets back on. This approach has worked for a while, but it is starting to be a bit of a maintenance burden: certain widgets need to be disabled for other reasons (hardware has entered a state where certain functionality is unavailable). The code for widget enabling/disabling is starting to smell bad. I am now in search of a cleaner solution to the button mashing problem.
    Maybe it is enough to restructure the code for managing which object is enabled and which is not? It should in general be pretty easy to implement a manager which tracks the tri-state (enabled, implicitly disabled, explicitly disabled) value of the enabled property of an object.

    Ideally, if a slot on the Manager is currently executing, additional signals connected to the slot will be ignored, or perhaps two or three signals would be queued, and subsequent signals discarded until the slot is done executing.

    I've done a bit of searching but I have not been able to articulate my problem very well to Google (I hope I have done an OK job of describing it here...)

    Qt::BlockingQueuedConnection does not do what I need.

    Have I just designed my application badly?
    Is there a name for a design pattern that I can try to understand, that either does not have this problem, or solves it elegantly?
    Any insight or guidance would be greatly appreciated.
    Why not simply queue jobs and execute them in sequence? When a job finishes execution, it checks if there are more jobs queued, takes the first one and executes.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  3. The following user says thank you to wysota for this useful post:

    jms (7th December 2014)

  4. #3
    Join Date
    Nov 2011
    Posts
    4
    Thanks
    2
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Prevent signals from "stacking up"?

    Why not simply queue jobs and execute them in sequence? When a job finishes execution, it checks if there are more jobs queued, takes the first one and executes.
    I think this is what I needed to hear. I need to spend a little time thinking about it, but I think I could make that work... and it would bring some other unrelated advantages.

    Thanks!

  5. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Prevent signals from "stacking up"?

    For completeness, here is an example of using a manager for enabling and disabling widgets.

    Qt Code:
    1. #include <QtWidgets>
    2.  
    3. class EnabledManager;
    4.  
    5. class EnablableWidget : public QObject {
    6. Q_OBJECT
    7. Q_PROPERTY(bool enabled READ isEnabled NOTIFY enabledChanged)
    8. public:
    9. EnablableWidget(QWidget *widget, QObject *parent = 0) : QObject(parent) {
    10. m_widget = widget;
    11. connect(this, SIGNAL(enabledChanged(bool)), m_widget, SLOT(setEnabled(bool)));
    12. }
    13. QWidget *widget() const { return m_widget; }
    14. bool isEnabled() const { return !(m_implicitlyDisabled || m_disabled); }
    15.  
    16. public slots:
    17. void setDisabled(bool val = true) {
    18. if(m_disabled == val) return;
    19. m_disabled = val;
    20. if(!m_implicitlyDisabled) emit enabledChanged(!m_disabled);
    21. }
    22. void setImplicitlyDisabled(bool val = true) {
    23. if(m_implicitlyDisabled == val) return;
    24. m_implicitlyDisabled = val;
    25. if(!m_disabled) emit enabledChanged(!m_implicitlyDisabled);
    26. }
    27. signals:
    28. void enabledChanged(bool);
    29. private:
    30. QWidget *m_widget = 0; //C++11
    31. bool m_disabled = false; //C++11
    32. bool m_implicitlyDisabled = false; //C++11
    33. };
    34.  
    35. class EnabledManager : public QObject {
    36. Q_OBJECT
    37. public:
    38. EnabledManager(QObject *parent = 0) : QObject(parent) {}
    39. EnablableWidget* addWidget(QWidget *widget) {
    40. EnablableWidget * ew = entry(widget);
    41. if(!ew) {
    42. ew = new EnablableWidget(widget, this);
    43. m_widgets << ew;
    44. }
    45. return ew;
    46. }
    47. EnablableWidget *addWidget(EnablableWidget *ew) {
    48. if(m_widgets.contains(ew)) return ew;
    49. m_widgets << ew;
    50. return ew;
    51. }
    52.  
    53. EnablableWidget * entry(QWidget *widget) const {
    54. foreach(EnablableWidget *w, m_widgets) if(w->widget() == widget) return w;
    55. return 0;
    56. }
    57. public slots:
    58. void setDisabled(bool val) {
    59. foreach(EnablableWidget *ew, m_widgets) ew->setImplicitlyDisabled(val);
    60. }
    61. void setEnabled(bool val) { setDisabled(!val); }
    62. private:
    63. QList<EnablableWidget*> m_widgets;
    64. };
    65.  
    66. #include "main.moc"
    67.  
    68. int main(int argc, char **argv) {
    69. QApplication app(argc, argv);
    70. EnabledManager manager;
    71. QVBoxLayout *l = new QVBoxLayout(&w);
    72. QCheckBox *dAll = new QCheckBox("DISABLE");
    73. hl->addWidget(dAll);
    74. for(int i=0;i<5;++i) {
    75. QPushButton *pb = new QPushButton("BUTTON");
    76. l->addWidget(pb);
    77. EnablableWidget *ew = manager.addWidget(pb);
    78. QCheckBox *cb = new QCheckBox(QString::number(i+1));
    79. QObject::connect(cb, SIGNAL(toggled(bool)), ew, SLOT(setDisabled(bool)));
    80. hl->addWidget(cb);
    81. }
    82. l->addLayout(hl);
    83. QObject::connect(dAll, SIGNAL(toggled(bool)), &manager, SLOT(setDisabled(bool)));
    84. w.show();
    85. return app.exec();
    86. }
    To copy to clipboard, switch view to plain text mode 

    "DISABLE" does an implicit disable of all registered widgets, other checkboxes explicitly disable a particular button. You could build up on it by registering expressions that explicitly disable certain widgets when particular criteria are met. QML could come in very handy here.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


Similar Threads

  1. How to prevent "What's this?" on right click
    By d_stranz in forum Qt Programming
    Replies: 0
    Last Post: 25th November 2013, 22:04
  2. Replies: 2
    Last Post: 21st August 2011, 07:57
  3. Thread shall emit signals with "complex" argument
    By Boron in forum Qt Programming
    Replies: 8
    Last Post: 17th June 2010, 18:22
  4. "emit" keyword optional when calling signals?
    By will49 in forum Qt Programming
    Replies: 1
    Last Post: 21st November 2008, 01:13
  5. Translation QFileDialog standart buttons ("Open"/"Save"/"Cancel")
    By victor.yacovlev in forum Qt Programming
    Replies: 4
    Last Post: 24th January 2008, 19:05

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.