tags:

views:

1065

answers:

3

Hi,

I need to determine when my Qt 4.4.1 application receives focus.

I have come up with 2 possible solutions, but they both don’t work exactly as I would like.

In the first possible solution, I connect the focusChanged() signal from qApp to a SLOT. In the slot I check the ‘old’ pointer. If it ‘0’, then I know we’ve switched to this application, and I do what I want. This seems to be the most reliable method of getting the application to detect focus in of the two solutions presented here, but suffers from the problem described below.

In the second possible solution, I overrode the ‘focusInEvent()’ routine, and do what I want if the reason is ‘ActiveWindowFocusReason’.

In both of these solutions, the code is executed at times when I don’t want it to be.

For example, I have this code that overrides the focusInEvent() routine:

void
ApplicationWindow::focusInEvent( QFocusEvent* p_event )
{

  Qt::FocusReason reason = p_event->reason();

  if( reason == Qt::ActiveWindowFocusReason && 
      hasNewUpstreamData() )
  {
    switch( QMessageBox::warning( this, "New Upstream Data Found!",
                                  "New upstream data exists!\n"
                                  "Do you want to refresh this simulation?",
                                  "&Yes", "&No", 0, 0, 1 ) )
    { 
    case 0: // Yes
      refreshSimulation();
      break;
    case 1: // No
      break;
    }
  }
}

When this gets executed, the QMessageBox dialog appears. However, when the dialog is dismissed by pressing either ‘yes’ or ‘no’, this function immediately gets called again because I suppose the focus changed back to the application window at that point with the ActiveWindowFocusReason. Obviously I don’t want this to happen.

Likewise, if the user is using the application opening & closing dialogs and windows etc, I don’t want this routine to activate. NOTE: I’m not sure of the circumstances when this routine is activated though since I’ve tried a bit, and it doesn’t happen for all windows & dialogs, though it does happen at least for the one shown in the sample code.

I only want it to activate if the application is focussed on from outside of this application, not when the main window is focussed in from other dialog windows.

Is this possible? How can this be done?

Thanks for any information, since this is very important for our application to do.

Raymond.

A: 

Looking at the Qt docs it seems that focus events are created each time a widget gets the focus, so the sample code you posted won't work for the reasons you stated.

I am guessing that QApplication::focusedChanged does not work the way you want because some widgets don't accept keyboard events so also return null as the "old" widget even when changing focus within the same app.

I am wondering whether you can do anything with QApplication::activeWindow()

Returns the application top-level window that has the keyboard input focus, or 0 if no application window has the focus. Note that there might be an activeWindow() even if there is no focusWidget(), for example if no widget in that window accepts key events.

David Dibben
+1  A: 

When your dialog is open, keyboard events don't go to your main window. After the dialog is closed, they do. That's a focus change. If you want to ignore the case where the focus switched from another window in your application, then you need to know when any window in your application has the focus. Make a variable and add a little more logic to your function. This will take some care, as the dialog will lose focus just before the main window gains focus.

+1  A: 

I think you need to track the QEvent::ApplicationActivate event.

You can put an event filter on your QApplication instance and then look for it.

bool
ApplicationWindow::eventFilter( QObject * watched, QEvent * event )
{
    if ( watched != qApp )
        goto finished;

    if ( event->type() != QEvent::ApplicationActivate )
        goto finished;

    // Invariant: we are now looking at an application activate event for
    //            the application object
    if ( !hasNewUpstreamData() )
        goto finished;

    QMessageBox::StandardButton response =
            QMessageBox::warning( this, "New Upstream Data Found!",
                                  "New upstream data exists!\n"
                                  "Do you want to refresh this simulation?",
                                  QMessageBox::Yes | QMessageBox::No) );

    if ( response == QMessageBox::Yes )
      refreshSimulation();

finished:
    return <The-Superclass-here>::eventFilter( watched, event );
}

ApplicationWindow::ApplicationWindow(...)
{
    if (qApp)
        qApp->installEventFilter( this );
    ...
}
Michael Bishop