tags:

views:

327

answers:

3

I am currently working on an application that launches separate processes which display additional dialogs. The feature I am trying to implement is simulating modal behavior of these dialogs. More specifically, I need the application to stop processing all input, both mouse and keyboard, when the dialog is launched, and resume when it's closed.

It is not so important for the dialog to remain on top of the application, although if you can suggest how to do that without resorting to Always-On-Top behavior, that would be nice as well.

To note, the application is compiled under both Windows and Linux. Also, it is not an option to launch the dialogs directly. They are in separate executables. Also the application is a pretty complex piece of software, so disabling widgets individually is not an option, or at least a not very viable one.

I found lock() and unlock() functions in QApplication class in Qt 3.3. We are currently using Qt 4.5, which doesn't seem to have that API. As a matter of fact, Qt 4.5 QApplication class doesn't seem to provide access to the Event Loop either.

To summarize: How do I disable/enable user input in a Qt Application, both mouse and keyboard shortcuts?

+2  A: 

To get full access to the application wide events, use QObject::installEventFilter() or QCoreApplication::setEventFilter() on your application object.
If your filter function returns true, Qt stops further processing of the event.

To not get too platform specific with the forwarding of the events to your other applications, i'd go for a suitable IPC mechanism.

Georg Fritzsche
Thanks, just discovered this myself about 10 minutes ago. Works like a charm.
Andrew Potapov
By the way. _setEventFilter()_ is not a good idea. It seems to set the Event filter permanently. _QObject::installEventFilter()_ and _QObject::removeEventFilter()_ worked better for me. Reference: http://doc.trolltech.com/4.5/eventsandfilters.html
Andrew Potapov
Be sure you're not globally blocking events if you do this, if you actually want some interaction to still work (such as signals/slots between threads, etc).
Caleb Huitt - cjhuitt
@cjhuitt Right. I'm only filtering user input events. I posted my solution in an answer bellow.
Andrew Potapov
+1  A: 

As an alternative answer, you can create your own event loop and start running it if necessary. You would need to create a QEventLoop object, connect a signal from another process to its quit() slot (such as from a QProcess that you are running your other program in), then exec() the loop. If I read things correctly, nothing will be handled by your main event loop while that loop is running.

Caleb Huitt - cjhuitt
Of course you have to be careful, and make sure the paint events are still handled correctly. Otherwise the main application looks like a mess if you try to move the child dialog around. Interesting approach though.
Andrew Potapov
A: 

gj already proposed this solution but I thought I'd paste my implementation just for reference:

Implement a filter class that will absorb user input actions.

class BusyAppFilter : public QObject
{
protected:
    bool eventFilter( QObject *obj, QEvent *event );
};


bool BusyAppFilter::eventFilter(QObject *obj, QEvent *event)
{
    switch ( event->type() )
    {
    case QEvent::KeyPress:
    case QEvent::KeyRelease:
    case QEvent::MouseButtonPress:
    case QEvent::MouseButtonDblClick:
    case QEvent::MouseMove:
    case QEvent::HoverEnter:
    case QEvent::HoverLeave:
    case QEvent::HoverMove:
    case QEvent::DragEnter:
    case QEvent::DragLeave:
    case QEvent::DragMove:
    case QEvent::Drop:
        return true;
    default:
        return QObject::eventFilter( obj, event );
    }
}

Then place this code your QApplication class:

QCursor busyCursor( Qt::WaitCursor );
setOverrideCursor( busyCursor );

BusyAppFilter filter;
installEventFilter( &filter ) ;

//... do the process stuff ...

removeEventFilter( &filter );

restoreOverrideCursor();
Andrew Potapov