Startup of more complex c++ applications is a problem. As an application developer you often don't have the ability to fix a lot of the issues related to this problem but there's one thing that bothers me a lot, that you, as an application developer can fix, so I decided to write about it a little today. I'll talk a bit about "delayed initialization" today.

Delayed initialization is one of those "unwritten rules" that you can read about on http://developer.kde.org/documentation/other/mistakes.html . In fact this entry should be added there. I don't have enough time but if you do, please try to format it as an entry there.

So how does a typical startup routine in a KDE application looks like? Well, first of all we have some KMainWindow derived class. For the purpose of my brainfarts here, let it be :
class MainWindow : public KMainWindow

And how does a typical main() look like in KDE? To make it very trivial lets say it's something along the lines of:
int main( int argc, char **argv)
KApplication a;

KCmdLineArgs *args = KCmdLineArgs:: parsedArgs();

MainWindow *window = new MainWindow( args );

a.setMainWidget( window );

return a.exec();
} The only thing that you have to see in this snippet is the fact that the MainWindow (which in some applications is actually a KUniqueApplication derivative or just a QWidget, either way it's the top level application object) is created before the event loop starts with a.exec().

This in turn means that before we get at all to the event loop of the application the main object has too be fully constructed. That in turn implies that we want to avoid doing any non-trivial task in the top-level constructor.

So what should you do? It's very simple: delay the construction of anything besides the GUI until the event loop starts. For example here's how our simple MainWindow should look like:
QTimer::singleShot( 0, this, SLOT(initObject()) );

void MainWindow::initGUI()
/* Here you construct the widgets. It's _very_ important
that each one of those widgets doesn't perform any non-gui
related function in the constructor as well.
All you want to do here is create the widgets and
QObject::connect them to each other */
void MainWindow::initObject()
/* This slot will be called as soon as we enter the event loop.
In here you put everything else. Restoring values, file
reads/writes/parses, document reading/restoring. everything
that doesn't simply create a GUI object */

Now what this means for users? It means that they will see the GUI for an application almost immediately. The fact that the app isn't yet functional when the GUI shows up doesn't really mean anything, because once you're in the event loop you can let users know you're not ready by either disabling the widgets of showing a progress bar while the app initializes. In most cases neither one will be even necessary as no one will start clicking right away on the app when it shows up. But it will have the cool effect of making your application seem a _lot_ faster even though you haven't done any real code optimizations :)


This is a good general idea, although I would add a little extension to it:

Why not add a splash screen while you are doing the post-init construction? Users will generally feel that the UI has been instantly created (and if the splash is big enough, you can bury some of the widget that aren't ready!), and in point of fact, they will often complain if the splash screen disappears too quickly after that, giving you more time.

Since the splash should be modal, that'll also prevent them clicking, and eliminate any confusion when they try and click on stuff quickly and find it not ready :)

By luke chatburn at Sun, 07/11/2004 - 18:23

Well, that wasn't the point I was trying to raise. I don't care whether you display progressbar, splashscreen or your picture while your app is loading. Granted the last one is a bad idea :)
I'm not a big fan of splashsreen's so I haven't even listed them. It's really up to you to pick the metaphor you're going to use to show your app is not ready.

By zack rusin at Sun, 07/11/2004 - 19:13

the thing about splash screens is they are a great idea, that is usually implemented as badly as possible to ensure they can suck when ever i try to defend them.

the big problem is on fast machines, the splashscreen is there, gone, and annoying. on slow machines, its there and the app looks like its frozen. KDevelop has a very nice and informitave splashscreen that gives nice feedback, while kontact's looks like something that was banned by the geneva convention.

the approach i have always used for Qt only apps for clients, is right after the QApplication is created i start a single shot timer that counts down from 500ms, if the app is not up the splash screen will show. similar to QProgress dialogs operation. Then the main window is done getting setup it checks to see if the splashscreen object is up and sets another timer and this one after 1 second the splashscreen goes away. This way its there long enough to give the user warm fuzzies when its doing what they want and wont piss them off when the app is up and running and they cannot use it. one other thing i use the splash screen for is to show status information. since kparts take their sweet time to load, its handy to show what you are doing that is taking so darn long.

that all being said, i think ripping this code out of the ctor and placing it in the init functions zack is talking about would make for a very usable situation. in an ideal world users should not see the splash screen, but when things are taking a little longer (ie the machine is swapping like hell so konqi takes 15 seconds to start vs 5) we can let the user know we are on our way. the worst possible thing we can do in a situtation of heavy system use is to NOT provide feedback. these situtations lead to my wife clicking the hell out of the konqi icon starting up 4 or 5 before the first one gets started, meanwhile the machine's disk is swapped into oblivion.

just my 2c though as someone who has users with KDE on a 128mb machine.

By Ian Reinhart Geiser at Sun, 07/11/2004 - 22:13