Debugging painting routines

I had the pleasure of building a custom page control last weekend. We are currently updating the style of the SmartInspect Console and wanted to replace the standard Windows page control in it. The standard control lacks a flat style and looks especially cumbersome under Windows 2000. After testing some controls from TMS and other third party vendors and not being satisfied with those controls, we decided to build our own. The result can be seen here:

Page Control

It doesn’t look too shabby I think and it only took me two days. I normally don’t build controls myself but while I developed the page control, I noticed how essential a logging tool like SmartInspect is for this task. It was impossible to debug the drawing routines and calculation of the tab widths with Delphi’s built-in debugger. The reason is quite simple: whenever the control draws itself and the IDE stops at a breakpoint, the control has to redraw itself again when it’s activated. This leads to an endless loop between the IDE and the drawing routine.

To solve this problem, I used the LogBitmap and LogCanvas methods of SmartInspect to log the different drawing states. This solved the debugging issue neatly since I was able to view every drawing step separately. I could then even use the Delphi debugger because I didn’t have to rely on viewing the drawn control in my test application but could see the output with SmartInspect.

This entry was posted in SmartInspect. Bookmark the permalink. Both comments and trackbacks are currently closed.

4 Comments

  1. Posted September 4, 2006 at 23:16 | Permalink

    That’s a way to do it, but using Delphi 2006 (maybe 2005 too) you can Use OutputDebugString and the messages will show up in the lower debug panel (which displays all the modules loaded etc).

    But it’s not as advanced as the smart inspect tool.

  2. Xepol
    Posted September 5, 2006 at 01:56 | Permalink

    I’ve developed MANY a component, and I have never found debugging paint routines to be very difficult. After all, it isn’t actually a loop – you are just responding to a wm_Paint command, and only one WM_Paint command can exist in the queue at any given time.

    Debugging is simple and easy even with the IDE debugger. You do, however get a WM_Paint message posted back to the queue when you are done debugging, so you can be sure that the code is going to fire again.

    Don’t want to debug the next loop? Turn off the break point.

    I do occasionally use the built in Debug logger, but only for a single piece of information typically. A thousand details can be a real pain to read through, it is just easier to trace the debugger.

    Worth noting here is the wm_EraseBkgnd message. You component recieves one before a wm_paint MOST of the time, and a wm_paint command usually follows a wm_erasebkgnd most of the time. The standard windows AND vcl handlers just paint the window the default background color. THis means that your component can flicker.

    If you want to avoid said flickering, call .Paint in response to wm_erasebkgnd -> there, nice huh?

  3. Posted September 5, 2006 at 08:58 | Permalink

    Not tried it yet, but I have a dual monitor system on order, which I am hoping will allow for debug on one screen with app in the other. WOuld this have worked in your case?

    Nice lookin control By the way.

  4. Posted September 5, 2006 at 22:16 | Permalink

    Thanks for the comments!

    Davy: OutputDebugString is a low level way of logging and I agree that it can be useful. If I recall correctly, you could view the OutputDebugString messages in Delphi 5 and Delphi 7 too, but I could be wrong (in Delphi’s Event Log debug window).

    Xepol: You are right that it IS possible to debug painting routines, but I found it much harder to do without logging the canvas object. If you have multiple painting steps, it’s nice to view the results of the different steps with a logging tool.

    I actually had to fight with flicker a bit while I developed the control. It’s probably a visual component writing newbie error. :-) The control is painting very smooth now and I fixed the flickering with a combination of DoubleBuffer and ignoring wm_EraseBkgnd where allowed. I will try calling my Paint method when wm_EraseBkgnd arrives, as it sounds like a smart tip.

    Jason: I actually have two monitors but I haven’t tried putting the debugged program on the second screen while debugging the painting code. I will try that though! But two screens are very useful for having docs on one screen and the IDE on the other one and I just love the setup.