Thursday, August 20, 2009

Disabling a TreeView Control

In my post “Setting the Background Color of a TreeView Control”, I presented some code that sets the background color of a TreeView to make it appear disabled. However, a reader named Alberto pointed out that after running that code, indented nodes have an ugly white background in front of them. I played with this a bit but couldn’t come up with a way to fix it.

Fortunately, there’s another solution: using a “lightbox”. Bernard Bout blogged about using the VFPX GDIPluxX project to create an image with a darker representation of a form and overlaying the form with the image to make the entire form appear disabled. I adapted his code to do the same thing with a TreeView control. Pass this code up to four parameters:

  • A reference to the form the TreeView is on.
  • A reference to the TreeView itself.
  • .T. to enable the TreeView or .F. to disable it
  • Optionally, an RGB value to use as the disabled color. If this isn’t passed, grey—RGB(240, 240, 240)—is used. This parameter isn’t used if the third parameter is .T.

This code creates an image object, takes a snapshot of the TreeView contents, makes the snapshot darker so it appears disabled, and uses the snapshot as the picture for the image. Note that a VFP control can’t cover an ActiveX control, so the code hides the TreeView. Of course, to the user, it looks like the TreeView is still there but disabled because the image is placed exactly where the TreeView is and contains a picture that looks just like a disabled version of the TreeView.

This code requires System.APP, which comes with GDIPlusX.

lparameters toForm, ;
toTreeView, ;
tlEnable, ;
tnColor
local llImage, ;
lnWidth, ;
lnHeight, ;
lnColor, ;
lnFactor, ;
lnRed, ;
lnGreen, ;
lnBlue, ;
loClrMatrix, ;
loBmp, ;
loGfx, ;
lcFile

* See if the specified form has a LightBox image.

llImage = pemstatus(toForm, 'imgLightBox', 5)
do case

* It does and we're supposed to enable the TreeView, so hide the image and
* redisplay the TreeView.

case tlEnable and llImage
toForm.imgLightBox.Visible = .F.
toForm.imgLightBox.PictureVal = ''
toTreeView.Visible = .T.

* We're supposed to disable the TreeView, so ensure GDIPlusX libraries are
* open and create the image if necessary.

case not tlEnable
do System.app
if not llImage
toForm.AddObject('imgLightBox', 'Image')
endif not llImage

* Size the image as necessary.

lnWidth = toTreeView.Width
lnHeight = toTreeView.Height
with toForm.imgLightBox
.Top = toTreeView.Top
.Left = toTreeView.Left
.Width = lnWidth
.Height = lnHeight
endwith

* If we weren't passed a color to use, use grey.

if vartype(tnColor) = 'N'
lnColor = tnColor
else
lnColor = rgb(240, 240, 240)
endif vartype(tnColor) = 'N'

* Get the colors we'll need.

lnFactor = 0.90 && 0 = Dark 1 = Bright
lnRed = bitand(lnColor, 0x000000FF) / 255 * lnFactor
lnGreen = bitrshift(bitand(lnColor, 0x0000FF00), 8) / 255 * lnFactor
lnBlue = bitrshift(bitand(lnColor, 0x00FF0000), 16) / 255 * lnFactor

* Create a BMP of the desired color and use it as the picture for the image.

with _Screen.System.Drawing as xfcSystem of Source\System.PRG
loClrMatrix = .Imaging.ColorMatrix.New( ;
lnRed, 0, 0, 0, 0, ;
0, lnGreen, 0, 0, 0, ;
0, 0, lnBlue, 0, 0, ;
0, 0, 0, 1, 0, ;
0, 0, 0, 0, 1)
loBmp = .Bitmap.FromScreen(toForm.imgLightBox)
loBmp.ApplyColorMatrix(loClrMatrix)
loGfx = .Graphics.FromImage(loBmp)
loGfx.FillRectangle(.SolidBrush.New(.Color.FromARGB(10, 0, 0, 0)), ;
0, 0, lnWidth, lnHeight)
endwith
with toForm.imgLightBox
.PictureVal = loBmp.GetPictureValFromHBitmap()
.ZOrder(0)
.Visible = .T.
endwith
toTreeView.Visible = .F.
endcase

No comments: