{"id":295,"date":"2008-09-04T22:42:02","date_gmt":"2008-09-04T10:42:02","guid":{"rendered":"https:\/\/www.deltics.co.nz\/blog\/?p=295"},"modified":"2008-09-04T22:42:02","modified_gmt":"2008-09-04T10:42:02","slug":"making-a-splash","status":"publish","type":"post","link":"https:\/\/www.deltics.co.nz\/blog\/posts\/295\/","title":{"rendered":"Making A Splash"},"content":{"rendered":"<span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\">5<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span><p>OK, so who hasn&#8217;t done this a million times &#8211; adding a splash screen to a Delphi application.\u00a0 I&#8217;ve seen any number of &#8220;easy&#8221; ways to do this but during a session at <strong>Tech Ed &#8217;08<\/strong> this week I saw the latest in splash screen technology from Microsoft:\u00a0 <a href=\"http:\/\/blogs.msdn.com\/jgoldb\/archive\/2008\/08\/12\/what-s-new-in-wpf-3-5-sp1-splash-screen-to-improve-perceived-startup-perf.aspx\" target=\"_blank\">A SplashScreen API and build action supported by WPF 3.5 and VS 2008<\/a>.<\/p>\n<p>I immediately thought of my <strong>Application<\/strong> psuedo-class and object in <strong>Deltics.Forms<\/strong>.<\/p>\n<p><!--more--><\/p>\n<p>The basic requirements of a splash screen are:<\/p>\n<p style=\"padding-left: 30px;\">1. Show up as soon as possible<\/p>\n<p style=\"padding-left: 30px;\">2. Disappear when the application is ready for user input.<\/p>\n<p>In a Delphi application this isn&#8217;t too difficult and usually ends up with code similar to this in your project dpr file:<\/p>\n<pre class=\"delphi\">program MyApp;\r\n\r\nbegin\r\n  splash := TSplash.Create(NIL);\r\n  splash.Show;\r\n  try\r\n    Application.Initialize;\r\n    Application.CreateForm(MainForm, TMainForm);\r\n  finally\r\n    FreeAndNIL(splash);\r\n  end;\r\n  Application.Run;\r\nend;<\/pre>\n<p>Quite often you find that even your supposedly sluggish application actually starts up so quickly that your beautiful splash screen is visible for barely enough time for your graphical prowess to be appreciated, so you add in a couple of <strong>Sleep()<\/strong> calls.  You also usually find that the splash screen isn&#8217;t drawing properly so you need to force a repaint &#8230;.  suddenly, instead of being a minor creative flourish your splash screen code is starting to somewhat dominate your project source!<\/p>\n<p>The WPF\/Visual Studio BuildAction approach starts to have some obvious appeal.<\/p>\n<p>But the WPF implementation also has a rather significant drawback &#8211; it&#8217;s just a pretty picture.<\/p>\n<p>Applications with the greatest need for splash screen are those with genuinely complex and lengthy initialisation needs, and those generally benefit from providing some sort of feedback to the user as to the progress of that initialisation, either as a progress bar or other feedback describing what is currently taking place.<\/p>\n<p>Just throwing an image up is not good enough, but the usual approach in Delphi &#8211; although more flexible &#8211; is undeniably cumbersome.<\/p>\n<p>Can we not devise something that is easy to use <span style=\"text-decoration: underline;\">and<\/span> flexible?<\/p>\n<p>Of course we can, and what is more, I realised that I already had the framework in place to enable it.<\/p>\n<h3>Once More Unto The Breach, Deltics.Forms<\/h3>\n<p>You may recall we previously dipped into a unit of mine &#8211; <strong>Deltics.Forms<\/strong>.  This unit provided some Vista compatibility code and in so doing introduced <a href=\"https:\/\/www.deltics.co.nz\/blog\/?p=222\" target=\"_blank\">an extended Application object<\/a>, providing a number of additional useful application services.<\/p>\n<p>What is a splash screen if not just such a useful application service?<\/p>\n<p>So I added two properties to my TApplication class:<\/p>\n<pre class=\"delphi\">  property SplashClass: TFormClass read get_SplashClass write set_SplashClass;\r\n  property SplashScreen: TForm read get_SplashScreen;<\/pre>\n<p>Of course, my <strong>TApplicationHelper<\/strong> class is effectively a class helper so I could not introduce any member variables, but since there is only one <strong>Application<\/strong> object I can use unit variables instead and provide getters and setters to &#8220;redirect&#8221; application properties to unit variables as required.<\/p>\n<p>In this case, due to the way I intended to implement this feature, I only needed one additional variable:<\/p>\n<pre class=\"delphi\">  var\r\n    _SplashScreen: TForm = NIL;\r\n\r\n  function TApplicationHelper.get_SplashClass: TFormClass;\r\n  begin\r\n    if Assigned(_SplashScreen) then\r\n      result := TFormClass(_SplashScreen.ClassType)\r\n    else\r\n      result := NIL;\r\n  end;\r\n\r\n  function TApplicationHelper.get_SplashScreen: TForm;\r\n  begin\r\n    result := _SplashScreen;\r\n  end;<\/pre>\n<p>The setter for <strong>SplashClass<\/strong> is a bit more involved because it takes care of instantiating the splash screen form itself and ensuring that it is correctly configured for use <em>as<\/em> a splash screen:<\/p>\n<pre class=\"delphi\">  procedure TApplicationHelper.set_SplashClass(const aValue: TFormClass);\r\n  begin\r\n    ASSERT(NOT Assigned(_SplashScreen), 'Already showing a splash screen');\r\n\r\n    _SplashScreen := aValue.Create(NIL);\r\n\r\n    with _SplashScreen do\r\n    begin\r\n      \/\/ Remove window frame and border decorations, set form to stay on\r\n      \/\/  top and center on the screen.\r\n      Caption     := '';\r\n      BorderStyle := bsNone;\r\n      BorderIcons := [];\r\n      FormStyle   := fsStayOnTop;\r\n      Position    := poScreenCenter;\r\n\r\n      \/\/ Display the form and force painting\r\n      Show;\r\n      Update;\r\n    end;\r\n\r\n    \/\/ The application may not have much initialisation so to avoid\r\n    \/\/  a blink and you miss it splash, we shall force a pause of\r\n    \/\/  1\/2 a second\r\n\r\n    Sleep(500);\r\n  end;<\/pre>\n<p>I could take care of all the look and feel issues when designing the form destined for use as a splash screen, but why bother, and why have to do that for every splash screen I design, when I can put that housekeeping in a place where it is sure to be applied?<\/p>\n<p>So, to have a splash screen in an application using <strong>Deltics.Forms<\/strong> all I need now is:<\/p>\n<p style=\"padding-left: 30px;\">1) A form for use as a splash screen<\/p>\n<p style=\"padding-left: 30px;\">2) One line of code in the project source<\/p>\n<p>Something a little like this:<\/p>\n<pre class=\"delphi\">begin\r\n  Application.SplashClass := TSplashScreenForm;\r\n  Application.Initialize;\r\n  Application.CreateForm(MainForm, TMainForm);\r\n  Application.Run;\r\nend;<\/pre>\n<p>But isn&#8217;t this only half the story?  We&#8217;ve seen that setting a splash class is enough to summon a splash screen, but how and when does the splash screen get dismissed?<\/p>\n<p>Well, once again the <strong>TApplicationHelper<\/strong> provides the necessary &#8220;hook&#8221;. <strong> Application.Run<\/strong> gets called at the point that any application is ready for the user to take over, and since the <strong>Application<\/strong> here is a <strong>Deltics.Forms.TApplicationHelper<\/strong> I can replace the usual <strong>Run<\/strong> method with my own:<\/p>\n<pre class=\"delphi\">  procedure TApplicationHelper.Run;\r\n  begin\r\n    \/\/ If we're showing a splash screen then we want to ensure that the\r\n    \/\/  main form becomes visible first before the splash screen is\r\n    \/\/  dismissed.  Again, to avoid a blink and you miss it splash screen\r\n    \/\/  we pause for 1\/2 a second before dismissing the splashscreen and\r\n    \/\/  actually allowing the application to run.\r\n\r\n    if Assigned(_SplashScreen) then\r\n    begin\r\n      MainForm.Show;\r\n      MainForm.Update;\r\n      Sleep(500);\r\n      FreeAndNIL(_SplashScreen);\r\n    end;\r\n\r\n    inherited;\r\n  end;<\/pre>\n<p>The most important thing here is of course to remember to call inherited so that the &#8220;genuine&#8221; <strong>TApplication.Run<\/strong> method is called.<\/p>\n<p>This also ensures that the application <strong>MainForm<\/strong> is presented for a reasonable (i.e noticeable, but not frustrating) period before the splash screen disappears.  This might sound trivial but I personally find it a gratifyingly &#8220;correct&#8221; behaviour, although I can&#8217;t quite put my finger on why.<\/p>\n<h3>Advanced SplashScreen Feedback<\/h3>\n<p>Having invoked a splash screen by assigning a class to the <strong>SplashClass<\/strong> property, the actual splash form is then accessible via the <strong>Application.SplashScreen<\/strong> property.<\/p>\n<p>At the most basic level this means that application startup code can get at the splash screen to provide any feedback that might be needed &#8211; this will require typecasting as things stand as the <strong>SplashScreen<\/strong> property is a simple <strong>TForm<\/strong> (actually, <strong>Deltics.Forms.TForm<\/strong>), so for example:<\/p>\n<pre class=\"delphi\">  TSplashScreenForm(Application.SplashScreen).lblProcess := 'Loading packages...';<\/pre>\n<p>Whether I will devise a general mechanism for updating splash feedback, I am not sure.  At the moment I&#8217;m thinking not.  Most such splash screens I think will have fairly unique needs and the implementer of any more advanced splash screen form class could easily provide simple helper methods encapsulating the necessary incantations if required:<\/p>\n<pre class=\"delphi\">unit SplashScreenForm;\r\n\r\n  \/\/ ... unit containing the splash screen form class also declares the below\r\n  \/\/ procedure in the interface to be called during startup as required\r\n\r\n  procedure SetSplashProcess(const aProcess: String);\r\n  begin\r\n    if Assigned(Application.SplashScreen) then\r\n      TSplashScreenForm(Application.SplashScreen).lblProcess := aProcess + '...';\r\n  end;\r\n\r\nunit MainForm;\r\n\r\n  :\r\n\r\n  uses\r\n    SplashScreenForm;\r\n\r\n  :\r\n\r\nprocedure TMainForm.FormShow(Sender: TObject);\r\nbegin\r\n    :\r\n  SetSplashProcess('Loading packages');\r\n    :\r\nend;<\/pre>\n<h3>Not Quite There Yet<\/h3>\n<p>I&#8217;m already pleased with how easy it proved to add this capability to my application helper.  I&#8217;m even more pleased that I can already see that the application concept will enable me to take this a step further and provide &#8220;built-in&#8221; support to all my applications for a splash screen suppression command line parameter.<\/p>\n<p>I haven&#8217;t implemented that yet, but it should be obvious that it will be a minor addition to the <strong>set_SplashClass<\/strong> property setter that will only instantiate a splash screen class if that suppression parameter is NOT present on the command line.<\/p>\n<h3>CodePlex &#8211; Not Going Well<\/h3>\n<p>Unfortunately as before, <strong>Deltics.Forms<\/strong> code is not yet available.\u00a0 The intention was to publish through CodePlex.\u00a0 The intention is still to publish, but CodePlex is falling out of favour.\u00a0 Performance of the Team Foundation repository that it uses is proving consistently diabolical over the net and it&#8217;s &#8220;querks&#8221;, to put it politely, intensely frustating.<\/p>\n<p>But I am working on it.<\/p>\n","protected":false},"excerpt":{"rendered":"<p><span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\">5<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span> OK, so who hasn&#8217;t done this a million times &#8211; adding a splash screen to a Delphi application.\u00a0 I&#8217;ve seen any number of &#8220;easy&#8221; ways to do this but during a session at Tech Ed &#8217;08 this week I saw the latest in splash screen technology from Microsoft:\u00a0 A SplashScreen API and build action supported [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":[]},"categories":[4],"tags":[54,292,44,55],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1TKYv-4L","jetpack_sharing_enabled":true,"jetpack-related-posts":[{"id":321,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/321\/","url_meta":{"origin":295,"position":0},"title":"Delphi 2009 Trial &#8211; First Impressions","date":"11 Sep 2008","format":false,"excerpt":"I imagine the news has spread like wildfire - the Delphi 2009 Trial Edition is now available for download!\u00a0 I got me one, and these are my initial impressions. 1. The Installation The installer itself is a small downloader stub, so the initial download is very quick.\u00a0 During installation of\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1525,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/1525\/","url_meta":{"origin":295,"position":1},"title":"RAD Studio in Auckland \/ Android in a VM \/ Touchy Feely","date":"30 Aug 2013","format":false,"excerpt":"Well, not really RAD Studio as such, more like Mobile Studio (whether as part of RAD Studio Ent+ or the Mobile Add-On) since everything shown was oriented around the Android support and emphasising the fact that an application written for iOS can simply be recompiled and will run on Android.\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"Androidx86","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Androidx86-1024x608.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":1945,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/1945\/","url_meta":{"origin":295,"position":2},"title":"Unit Aliases and Build Configurations","date":"17 Oct 2013","format":false,"excerpt":"Over on stackoverflow, Ann Gossard had a question about using an $ifdef in the project (DPR) uses list to use one unit in preference over another, specifically in debug builds. In this situation, it immediately occurred to me that unit aliases might be creatively deployed. What follows is a slightly\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2013-10-17-at-15.25.51.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":1938,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/1938\/","url_meta":{"origin":295,"position":3},"title":"Menu Items, APIs, Crackers and Hackers","date":"16 Oct 2013","format":false,"excerpt":"Francois Piette recently posted a solution to obtaining the screen position of a menu item involving using a \"hacker\" class. There is however a safer, more direct mechanism which I hope Francois won't mind me sharing and a far less safe related hacking technique that his post brought to mind.\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1954,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/1954\/","url_meta":{"origin":295,"position":4},"title":"Hands Off My Application! (Another DPR Trick)","date":"18 Oct 2013","format":false,"excerpt":"In a comment on my previous post, David Heffernan noted that the IDE messes around with other parts of the application DPR in addition to the uses list. He is right. Another area that the IDE likes to muck about with is the code in the DPR begin .. end\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2013-10-18-at-09.01.47.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":563,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/563\/","url_meta":{"origin":295,"position":5},"title":"Delphi Unicode = Wide-ANSI","date":"26 Sep 2009","format":false,"excerpt":"Be careful what you wish for. A lot of people were overjoyed to hear that Unicode support was coming to Delphi. Some were skeptical of the chosen implementation approach however, it all seemed just a little bit too easy. I was one, and sadly it seems I was right. I've\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/295"}],"collection":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/comments?post=295"}],"version-history":[{"count":8,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/295\/revisions"}],"predecessor-version":[{"id":303,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/295\/revisions\/303"}],"wp:attachment":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media?parent=295"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/categories?post=295"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/tags?post=295"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}