Send comments on this topic. | Back to Introduction - All Topics | Help Version 16.5.9.25
Implementing Custom Paint

This topic describes how to use custom callbacks in LEADTOOLS to implement painting to non-standard grayscale display adapters.

Overview:

There are several classes for implementing custom painting. These classes give you the ability to override some of the system painting functions to access extra features in advanced graphics displays. In particular, of interest are display adapters that can display more than 8-bit of grayscale colors.

To take advantage of these features, you can implement a RasterPaintCallbacks class and add it to the list of PaintCallbacks. An application that wants to support a number of graphics cards will create a class for each adapter and add them all to the RasterImage.PaintCallbacks list.

The list is required because the computer running the application might have more than one monitor and more than one display adapter. The user can drag the window from one monitor to another so you should populate the PaintCallbacks list with all the custom paint objects compatible with the display adapters in the system. Or you can just add all the display adapters you can support since the overhead for having unnecessary callbacks in the list is low.

Whenever the RasterImage object needs to paint, it will try all the custom callbacks objects until it finds one compatible with the current display adapter. If it doesn’t find any compatible object, it will paint using the default GDI functions.

For each RasterPaintCallbacks object, the RasterImage will do the following:

  1. Call its RasterImagePaintCallbackFunction.IsCompatibleDCCallback delegate function. If the function returns true, it will select that object to implement the painting and it will go to step 2. If the function returns false, the RasterImage object will try the next RasterPaintCallbacks in the list. If no compatible objects are found, the painting will default to the normal behavior.
  2. Call the RasterImagePaintCallbackFunction.PrePaintCallback once before painting starts. The application can perform memory allocation and initialization. This is the signal that the object has been selected to do the painting.
  3. Call all the other delegates as necessary.
  4. Call the RasterImagePaintCallbackFunction.PostPaintCallback delegate after painting finishes.

If the application adds a RasterPaintCallbacks object to the list without a IsCompatibleDCCallback delegate, that object will always be used to perform the paint. The remaining items in the RasterImage.PaintCallbacks list will not be queried.

All the paint callbacks are delegates that look the same (C++ syntax):

Object^ MyCallback(RasterImage^ image, array<Object^>^ Params)

The parameters are different for each callback and are passed through the Params parameter. See the PaintCallbacks topic for information on which parameters are passed for each callback type.

The parameters are for reading purposes only. A callback that needs to pass back information will do so through the return value. When more than one value needs to be returned, a class will be used for this purpose (see the RasterImagePaintCallbackFunction.GetDibInfoCallback callback for such an example).

You do not need to implement each callback. You can implement 1, 2, 3 or as many callbacks as you need. If a callback is not provided, the default internal callback will be used.

At the minimum, you should consider the following callbacks:

CallbackPurpose / Description
IsCompatibleDCCallbackTo test whether the HDC is compatible with your display adapter
GetDibInfoCallbackTo tell LEADTOOLS the type of data expected by the device
StretchDIBitsCallbackTo implement the actual painting
ConvertLineCallbackTo do the color conversion if the internal color conversion functions are not enough. It is recommended for you to try the internal conversion function first
PrePaintCallbackTo perform any memory allocation or initialization for the current paint
PostPaintCallbackTo free any memory that might have been allocated in PrePaintCallback

The callbacks are added to the RasterPaintCallbacks object using SetCallback. So the pseudocode might look like this:

/* Allocate and initialize the callback class */
myCallbacks = gcnew RasterPaintCallbacks();
myCallbacks->SetCallback(IsCompatibleDCCallback, myFunc1);
myCallbacks->SetCallback(GetDibInfoCallback, myFunc2);
/* Add the callbacks to the RasterImage object */
myRasterImage->RasterPaint->Add(myCallbacks);

Typically, one might implement the callbacks in C++ and then use that callback class from other languages such as C# or VB.NET. That is because many display card manufacturers will provide you with a C/C++ lib which is easiest to use from a C++ project.

NOTE: If you have to call some specialized 3rd party functions that require a screen DC handle, you must disable double buffering in the LEADTOOLS display control (DoubleBuffer). .NET implements double buffering by drawing to a memory DC and it is very likely that the special 3rd party functions will not work with memory DCs. So, it is recommended you start by disabling the double-buffer feature to make sure you eliminate any problems. Once you get your display working, you can re-enable the double-buffering and see if the 3rd party functions that you call will work with memory DC handles as well.