Workaround for WA_MacNoClickThrough

  • According to the docs, Qt::WA_MacNoClickThrough has no effect but I'm pretty sure it's exactly what I'm looking for. If the window has this attribute, then clicking on the window while it doesn't have focus will give it focus without producing a click event. But of course, the attribute no-longer does anything so how can I achieve this effect?

  • What's the reason for not wanting a click event? From what I understand, you want to provide focus to a widget without a click event.

    Does clicking increment something in your program that you want to avoid? My program does something similar, and I get around it by specifying increments to a variable for specific actions and not all actions.

    Understanding why exactly you want that functionality will help in finding an alternative solution to Qt::QA_MacNoClickThrough.

  • @chihwah I want the click to bring focus to the window and do nothing else. Imagine that there's some button that deletes something. The user clicks the window just to give it focus without thinking too hard about where they're clicking. They might accidentally hit the delete button. So it might make sense to give that delete button the attribute so that clicking on it while the window doesn't have focus won't delete anything.

  • You could connect the button to a slot that recognises whether the widget has focus or not using hasFocus(). If it doesn't, then it will give the widget focus through setFocus(), and if it does, then it will call another slot that performs the required action.

    Does that fit your requirements? Sorry for delay - because I haven't posted that much and my reputation is low the forum doesn't allow me to post more than once every 10 mins.

  • I've tried a few ways of checking if the window has focus but none have worked so far. I'm beginning to think that this isn't worth the effort.

  • @Kerndog73 Why is that - do you have a parent widget that has focus? It might have to do with the structure of your widgets...

  • @chihwah setFocus and hasFocus deal with a widget that has focus. I want to check if the window has focus. Calling hasFocus on the window is not what I'm after. This might not be possible because the window probably gained focus by the time we get to mousePressEvent. I think this might be too much effort for a very minor feature.

  • @Kerndog73 I see. Have you tried playing around with focus events? I'm not super familiar with QFocusEvent but seems like something that could maybe help?

    I'll have a play around later and see if I can get anywhere with that. Interested to see how it'll work as well!

  • @Kerndog73 I think I've found a solution.

    1. Make your delete button focus policy Qt::ClickFocus. This is because the solution will be based around focus functionality and you probably don't want the delete button to be activated when the user hits tab or scrolls around to the delete button.

    2. Implement the following line:
      connect(qApp, SIGNAL(focusChanged(QWidget*, QWidget*)), this, SLOT(sampleSlot(QWidget*, QWidget*)));

    This will provide a signal every time a focus changes, of QWidget *oldwidget and QWidget *newwidget respectively.

    1. In the Slot that the focusChanged signal triggers, use the following logic:
      if(newwidget = your delete button) then run the following code:
      if(oldwidget = nullptr) OR if(oldwidget->window() = newwidget->window()) then call the delete button functionality.
      If it doesn't satisfy the above conditions then do not c tallhe delete button functionality as the user would have been switching between two windows.

    2. The only remaining issue now is when the focus doesn't change (i.e. user clicks from another window onto the delete button, then clicks the delete button again). To get around this, create a global variable pointer. Then add another slot in to connect to the clicked signal of your delete button.

    3. In this new slot, check if your new global variable pointer = your delete button. If so, call the delete button functionality. At the end of this slot, assign your global variable pointer the value of your delete button. Also, add in at the start of the first slot, the following line: global variable pointer = nullptr. This will clear our your global variable pointer every time the focus changes.

    I have tested this logic and it works for me. Let me know if anything is unclear and I'll put my code examples in so it's easy to understand.

  • I don't think it is a good idea trying to implement this behaviour. It is good that you think about your users accidentally deleting something. However, I have not encountered this problem.

    The major point not to implement this is because it is unexpected behaviour. No software does this and it is more likely a point for user frustration instead of helping them. Maybe they have switched to another program shortly, e.g. a chat or similar. Your window is still (partially) visible and they want to get quickly back to work. So, they might be clicking your button on purpose, but nothing happens. They become frustrated because their (maybe fast) computer is too busy to register the click (at least in their perception). After a few seconds they notice that actually nothing happened and they click again. If this only happens for some of your application's buttons it is even more confusing. Maybe they actually figure out that clicking buttons in your application when it wasn't in focus requires two clicks. But, you haven't implemented it for all your buttons. Then the user clicks one of the buttons which does not support this behaviour twice as they have learned it. Suddenly, they have triggered the action twice. You cannot expect any user (other than yourself) to understand this.

    The potential problems I described above are magnified when someone has a multi-monitor setup with your app fullscreen on one of them.

    Try to stick to user interface guidelines to not annoy your users.

    I believe that users are trained to subconciously not click on buttons to bring an application back into focus.

Log in to reply