Chapter 9. Constructing A Responsive User Interface

by David Sweet

In this chapter

All too often, you have probably used GUI applications that fail to repaint their windows, leaving an empty, or partially empty frame on the screen, or you have used an application that begins a task and ignores you until it is done—not knowing if you preferred to abort the task rather than wait. In general, many applications—even popular, regularly used applications—at times provide no feedback or do not respond to user input. In this chapter you learn how to avoid writing code that behaves so poorly.

The methods presented in this chapter are not the only relevant ones. In particular, multithreading is continually gaining popularity as a way of separating GUI code from "back-end" work code. Qt is not currently thread-safe (thus, neither is KDE), but there are ways around this problem. Multithreading is beyond the scope of this book, but useful discussion of the subject exists in the qt-interest mailing-list archive at http://www.troll.no/qt-interest/.

9.1. The Importance of Responsiveness

Your application's interface needs to be constructed so that the user

  • Knows the current state of the application

  • Knows whether a command given to the application has been received

  • Knows that the application is working on a task and not simply "hung"

  • Can always control the flow of the program

It is generally simpler to think linearly about the functions your applications need to perform. Many of you may be intimately familiar with this style of programming from writing command-line interface programs. When writing for a GUI, of course, things are different. Your application needs to always be aware of the user interface—even while it is performing other tasks. Essentially, your application needs to perform rudimentary multitasking to keep the UI alive while still doing useful work.

To get a feel for the importance of a responsive UI, let's look at some common problems GUI application programmers come across (but don't always solve!).

Some windows can take a long time to repaint. During the repainting, the application gives no CPU cycles to the UI, and the user has to wait for the window to be completely updated before any mouse clicks or key presses are processed. Slow updates at best make the UI seem sluggish and at worst make the application unusable. Imagine if an automobile responded in a similar way: You turn the steering wheel and after a half-second or so, the wheels respond. This car would be quite difficult to control!

A similar problem occurs when your application must perform long jobs, such as connecting to another computer, searching a database, or filtering an image. It is tempting to write a method that performs the entire task and then returns, perhaps updating the display with the results of the computation, but the user will not be able to interact with your application, so the following problems occur:

  • The user cannot cancel the long job.

  • The application's windows will not get repainted. (They may need to be repainted if, for example, another window is dragged over them.)

  • The user cannot take advantage of other features of your application that might logically still be usable while the long job progresses.

Of course, while performing a long task, you should also let the user know that the task is progressing so that the user knows the application is working as expected. You should periodically update a window with a progress bar or something similar.