{"id":404,"date":"2008-09-29T22:04:32","date_gmt":"2008-09-29T10:04:32","guid":{"rendered":"https:\/\/www.deltics.co.nz\/blog\/?p=404"},"modified":"2008-09-29T22:04:32","modified_gmt":"2008-09-29T10:04:32","slug":"an-auto-cancelling-hourglass","status":"publish","type":"post","link":"https:\/\/www.deltics.co.nz\/blog\/posts\/404\/","title":{"rendered":"An Auto-Cancelling Hourglass"},"content":{"rendered":"<span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\">3<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span><p>As <a href=\"https:\/\/www.deltics.co.nz\/blog\/?p=391\" target=\"_blank\">promised last time<\/a>, I present here a very simple implementation of an automatically cancelling hourglass exploiting the same life-time management used previously to <a href=\"https:\/\/www.deltics.co.nz\/blog\/?p=391\" target=\"_blank\">automatically dispose of temporary objects<\/a>.<\/p>\n<p><!--more--><\/p>\n<h2>First, The Code And An Apology<\/h2>\n<p>[dm]11[\/dm]<\/p>\n<p>I have tested the download this time and it appears fine.<\/p>\n<p>Also a quick apology to anyone who experienced difficulty over the weekend accessing the site.\u00a0 Those problems should now have been resolved by my ISP.<\/p>\n<h2>Then, How It Is Used<\/h2>\n<p>As you will see if you download it, the implementation really is embarrasingly simply &#8211; the license and documentation is quite a bit more extensive than the code itself!\u00a0 This is most apparent in the usage itself, handled by just two functions, one of which is needed only occasionally:<\/p>\n<blockquote>\n<ul>\n<li>HourglassOn()<\/li>\n<li>HourglassOff()<\/li>\n<\/ul>\n<\/blockquote>\n<p>To turn the hourglass on, call <strong>HourglassOn()<\/strong>.<\/p>\n<p>You don&#8217;t actually need to do anything for it to be turned off!<\/p>\n<pre class=\"delphi\">  procedure TMyForm.ButtonOKClick(Sender: TObject);\r\n  begin\r\n    HourglassOn;\r\n    \/\/ Do your processing here\r\n  end;<\/pre>\n<p>Once your code leaves the scope in which you turned the hourglass on, the reference you created by calling <strong>HourglassOn()<\/strong> is released.  If that is the only reference then the hourglass will turn itself off again.  Even if your code calls other routines that in turn call <strong>HourglassOn()<\/strong>, the references will all be released and once all of them have been released, the hourglass goes off:<\/p>\n<pre class=\"delphi\">  procedure TMyForm.ButtonOKClick(Sender: TObject);\r\n  begin\r\n    HourglassOn;\r\n    \/\/ Do your processing here\r\n    SomeCommonProcessing;\r\n  end;\r\n\r\n  procedure TMyForm.SomeCommonProcessing;\r\n  begin\r\n    HourglassOn;\r\n    \/\/ Common processing code occurs here\r\n  end;<\/pre>\n<p>And as with <strong>AutoFree()<\/strong>, these references are released even where an unhandled exception is encountered or raised.<\/p>\n<p>So why even have an <strong>HourglassOff()<\/strong> facility?<\/p>\n<p>Honestly?<\/p>\n<p>I&#8217;m not sure.\u00a0 Certainly I don&#8217;t recall ever having to use it.\u00a0 It was implemented when I thought it may be useful to ensure that the hourglass is off prior to presenting a message box or other user interaction, but before I had realised that even this doesn&#8217;t appear to be necessary.\u00a0 I left it in just in case.<\/p>\n<p>You never know.<\/p>\n<p>\ud83d\ude42<\/p>\n<p><strong>HourglassOff()<\/strong> effectively clears the decks &#8211; any subsequent calls to <strong>HourglassOn()<\/strong> will effectively be managing an entirely new hourglass cursor.\u00a0 Any references to a prior existing hourglass will silently be released without interfering with the new cursor.<\/p>\n<h2>More Tinkering With (Deltics.)Forms<\/h2>\n<p>There is actually a third function that I&#8217;ve not mentioned so far: <strong>HourglassActive()<\/strong>.<\/p>\n<p>This returns a <strong>Boolean<\/strong> that indicates whether an hourglass (as represented by an hourglass object in this implementation) is currently active.\u00a0 This is used primarily by a recent change in my <strong>Deltics.Forms<\/strong> unit in a slight modification of the behaviour of <strong>ShowModal<\/strong>.<\/p>\n<p><strong>ShowModal<\/strong> saves the current <strong>Screen.Cursor<\/strong> at the time that a form is shown modally before applying a <strong>Screen.Cursor<\/strong> of <strong>crDefault<\/strong>.\u00a0 When the modal form has been dismissed, if <strong>Screen.Cursor<\/strong> has not been further modified the saved cursor is restored.\u00a0 If the modal form itself <em>has<\/em> changed the <strong>Screen.Cursor<\/strong> at all, the saved cursor is NOT restored.<\/p>\n<p>In <a href=\"https:\/\/www.deltics.co.nz\/blog\/?tag=delticsforms\" target=\"_blank\"><strong>Deltics.Forms<\/strong><\/a>, <strong>ShowModal<\/strong> has now been extended to also consider the <strong>HourglassActive()<\/strong> indicator.\u00a0 That is, regardless of whether the modal form has modified the <strong>Screen.Cursor<\/strong>, once a modal form is dismissed the hourglass cursor (NOT any saved cursor) is reinstated if <strong>HourglassActive()<\/strong> is <strong>TRUE<\/strong>.<\/p>\n<h2>Limitations<\/h2>\n<p>Firstly and most obviously of course, this is not a general purpose cursor management framework.\u00a0 It is solely concerned with simple use of an hourglass to indicate a &#8220;busy&#8221; state in an application.<\/p>\n<p>Secondly the implementation deals with hourglass control for processes entirely bounded by scope.\u00a0 If you have some process that encompasses separate scopes then there is the possibility of cursor flicker:<\/p>\n<pre class=\"delphi\">  procedure TMyForm.ButtonDoItClick(Sender: TObject);\r\n  begin\r\n    ProcessPart1;\r\n    ProcessPart2;\r\n  end;\r\n\r\n  procedure TMyForm.ProcessPart1;\r\n  begin\r\n    HourglassOn;\r\n    \/\/ Do some processing\r\n  end;\r\n\r\n  procedure TMyForm.ProcessPart2;\r\n  begin\r\n    HourglassOn;\r\n    \/\/ Do some other processing\r\n  end;<\/pre>\n<p>In this case the cursor will toggle between hourglass and default states for each of <strong>ProcessPart1<\/strong> and <strong>ProcessPart2<\/strong> as the hourglass turned on by each is turned off when each completes.  Usually this sort of situation is easily resolved by ensuring that the hourglass is turned on in the event &#8211; originating in the GUI &#8211; that spans the scopes involved, i.e. that calls the methods.<\/p>\n<p>Other than that, this very simple implementation has served me well, although it has not perhaps been exercised over rigorously.<\/p>\n<h2>Caveat Developor<\/h2>\n<p>I should point out that, as <a href=\"https:\/\/www.deltics.co.nz\/blog\/?p=391#comments\" target=\"_blank\">Barry Kelly mentioned in the comments to the <strong>AutoFree()<\/strong> post<\/a>, the behaviour on which this relies (or perhaps more specifically the precise <em>timing<\/em> of the behaviour) is not a formally defined aspect of the language or the run-time, and so cannot be guaranteed in future Delphi versions.<\/p>\n<p>He is better placed than I (<a href=\"http:\/\/www.blogger.com\/profile\/10559947643606684495\" target=\"_blank\">he actually works on the Delphi compiler!<\/a>) to know, but I would be very surprised if this behaviour did change as there may well be code &#8220;in the wild&#8221; &#8211; quite apart from that which I&#8217;ve presented recently &#8211; that relies on, or is at least sensitive to, this timing.<\/p>\n<p>For myself I&#8217;m not overly concerned &#8211; Barry wasn&#8217;t saying that it <em>would<\/em> change, only that it <em>could<\/em>.<\/p>\n<p>Never-the-less, I guess I should consider myself warned.\u00a0 And, now, so too should you.<\/p>\n<p>\ud83d\ude42<\/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\">3<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span> As promised last time, I present here a very simple implementation of an automatically cancelling hourglass exploiting the same life-time management used previously to automatically dispose of temporary objects.<\/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":[292,44,66,67],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1TKYv-6w","jetpack_sharing_enabled":true,"jetpack-related-posts":[{"id":391,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/391\/","url_meta":{"origin":404,"position":0},"title":"Free Yourself","date":"27 Sep 2008","format":false,"excerpt":"Barry Kelly recently posted an example of \"smart\" pointers (specifically the auto-pointer variant of a smart pointer) using generics in Delphi 2009.\u00a0 It was an interesting use of generics but the end result was something that has - in part at least - been possible for some time in Delphi\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":375,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/375\/","url_meta":{"origin":404,"position":1},"title":"Delphi 2009 &#8211; StringPerformance Redux","date":"22 Sep 2008","format":false,"excerpt":"It looks like I may have jumped the gun with my conclusions from the previous exercise to benchmark string performance in Delphi 2009.\u00a0 Following a useful exchange in the comments with Kryvich I corrected a small discrepancy in the tests and made some changes to the performance testing subsystem within\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/delphi2009-stringperformance-chart.jpg?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":160,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/160\/","url_meta":{"origin":404,"position":2},"title":"MultiCast Events &#8211; Conclusion","date":"11 Aug 2008","format":false,"excerpt":"Drawing this subject to a close (finally!), here's the concluding post I promised, including the fully documented and finished implementation that has been serving me well for almost 2 years.\u00a0 The finished implementation incorporates a number of refinements to the core framework, and those are what we shall briefly look\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":349,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/349\/","url_meta":{"origin":404,"position":3},"title":"Delphi 2009 &#8211; String Performance","date":"18 Sep 2008","format":false,"excerpt":"NOTE: Downloads are now fixed! Andreas Hausladen generously took the time to make some detailed comments on my previous post, one of which prompted me to throw together some further performance test cases for String types specifically.\u00a0 The results were something of a mixed bag and contained some surprises. The\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/delphi2009-stringperformance-resultscapture.jpg?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":1300,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/1300\/","url_meta":{"origin":404,"position":4},"title":"What&#8217;s in a Name(space) ?","date":"28 Nov 2012","format":false,"excerpt":"The ever evolving DWScript project continues to advance the Pascal language at an impressive pace. Just today it was announced that this scripting version of Pascal now has \"namespace\" support. When I first read the details of the implementation, my initial reaction was that it \"felt a bit backwards\". The\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1207,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/1207\/","url_meta":{"origin":404,"position":5},"title":"Adventures in Syntax: Something Old, Something New etc&#8230;","date":"20 Sep 2012","format":false,"excerpt":"As the post title says, this will be a brief detour through some features of the Pascal language and a presentation of some (theoretical) alternatives that could have been introduced instead. That is, some are real but little known syntax, others are what I think might be preferable to the\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\/404"}],"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=404"}],"version-history":[{"count":6,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/404\/revisions"}],"predecessor-version":[{"id":410,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/404\/revisions\/410"}],"wp:attachment":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media?parent=404"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/categories?post=404"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/tags?post=404"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}