a lightbox dialog technique in vfp

you may or may not have heard of the lightbox dialog ui effect. it is one of the current effects making the rounds, and has been described as the "interaction design technique of the year" on this page where design awards for 2008 were announced -

http://www.useit.com/alertbox/application-design.html (scroll down midway)

well this effect can very easily be implemented in vfp with a simple image and a png with a mask.

you may recall that i showed the usage of png's with transparent masks to enhance the gui in these posts:

http://weblogs.foxite.com/bernardbout/archive/2006/09/11/2436.aspx

http://weblogs.foxite.com/bernardbout/archive/2006/11/04/2798.aspx

and showed a technique for embedding images in these:

http://weblogs.foxite.com/bernardbout/archive/2007/02/18/3320.aspx

http://weblogs.foxite.com/bernardbout/archive/2007/07/15/4366.aspx

at the end of this post will be a class where you can get this lightbox effect in your vfp applications. it uses a masked png that is "embedded" into the class so no external files are needed.

the class is just dropped on a form or into a container on the form and when needed, the display() method is called passing a couple of parameters. as described elsewhere, the lightbox is useful to focus a user's attention on a modal messagebox. therefore the display() method needs to be called just before displaying the modal form and after to remove it.

the sample form provided shows how this can be called using the vfp messagebox() but you can very easily substitute that for your own modal messagebox form as per your own design. that is beyond the scope of this post, which is just about the lightbox class.

here the class is added to the form as well as a container in the form in the vfp ide.

this is the code from a method called from the exit button:

lparameters tcmsg
local lret as boolean
thisform.lightbox1.display(.f.,.t.)
if messagebox(tcmsg,292,"are you sure?",0) = 7
   lret = .f.
else
   lret = .t.
endif
thisform.lightbox1.display()

return lret

the display() method is called with 2 optional parameters. the first parameter is the object over which the lightbox will be overlaid, and if .f. , the parent object is assumed. the second is to switch the class on or off.

thisform.lightbox1.display(.f.,.t.)
means show the lightbox for the form(default)

this shows the form running. the lightboxes are not visible.

 

here the container lightbox is toggled on

 

and finally the lightbox class in action on the form. see how it emphasises the messagebox?

this effect makes the messagebox stand out and being modal, the user is forced to read the message and act on it. as i said earlier, it is not too difficult to use your own custom messagebox. all that is required is to insert a call to the lightbox.display() just before showing the messagebox and immediately after, to hide it.

enjoy.

 19/08/2008 update

thanks to cyril & cesar for finding this. the class had deleted records hence the image mask was not loading. download has been updated. also png's changed to bmp because of vfp handling of png's. please download latest version below.

19/08/2008 2nd update

this tip is from cesar (http://weblogs.foxite.com/vfpimaging)

with this tip you can implement the lightbox class with very few changes as it wraps your original messagebox() calls.

where ever you want to use the lightbox class along with a messagebox() - example is for the exit button:click()

#define messagebox lightboxmsgbox

if messagebox("are you sure you want to quit",292,"are you sure?",0) = 7
return
else
thisform.release
endif

then, create a small prg that will wrap the original messagebox command call it lightboxmsgbox.prg

lparameters tcmessage, tntype, tctitlebartext, tntimeout

local loform as form
loform = _screen.activeform
loform.lightbox1.display(.f.,.t.)

local llreturn as boolean
llreturn = messagebox(tcmessage, tntype, tctitlebartext, tntimeout)
loform.lightbox1.display()
return llreturn

this way, you wont need to change any code in your forms, just add the line below

#define messagebox lightboxmsgbox

in a header ".h" file, linked to your forms class. great tip cesar.

20/08/2008

updated zip file to v1.03. new property maskfile to use an external maskfile.

this is because only vfp9sp2 handles png's properly when using the pictureval property. if the property is left empty then it will load the internal png - (for sp2)

also corrected version of cesar's sample code.

[snip]

messagebox() command returns integer values, not boolean, so the function will stay better this way:

lparameters tcmessage, tntype, tctitlebartext, tntimeout

* some few tweaks in the parameters, in order to make messagebox()

* work as desired, for the case when some parameters are missing

tntype = evl(tntype, 0)

if vartype(tctitlebartext) "c"

   tctitlebartext = "microsoft visual foxpro"

endif

if not vartype(tntimeout) $ "ni"

    tntimeout = 0

endif

* find the lightbox object and activate it

if type("_screen.activeform.name") "c" 

    * could not locate an active form

     return

endif

local loform as form

loform = _screen.activeform

loform.lightbox1.display(.f.,.t.)

* call the original messagebox() command

local lireturn as integer

lireturn = messagebox(tcmessage, tntype, tctitlebartext, tntimeout)

* deactivate the lightbox

loform.lightbox1.display()

return lireturn

this function probably still needs some tweaks, specially at the part for locating the lightbox object.

[endsnip]
unfortunately because of the amount of junk mail being generated from the weblog i have switched off comments. please post your comments, if any, at www.foxite.com

10 Responses to LightBox Class – More with embedded PNG’s

  • Cyril Baskir says:

    Bernard, thanks for your lightbox contribution.

    I ran the form but it appears the mask image is missing (shows an “X”). Did I miss a step?

    Hi Cyril
    The mask image is embedded in the class so there is no need to include it. Try one thing-add the class to a form and make it a bit bif. Set the Visible = .T. of the class. Run the form. Do you see the mask? If not put a breakpoint in the init of the class where it loads the image and see what is returned in cPixStr.
    Thanks for your feedback.

  • Michael says:

    One more thing, Clicking “Toggle” button few times raise shadow of “globe” image after every click.

    Cannot help that. That is VFP handling of PNG’s. You will not see this with a bitmap. The globe was just a sample and not needed for this to work.

  • Dale says:

    Nice job, Bernard! And the implementation is simple.

  • Cesar says:

    Hi Bernard !
    AWESOME !

    You’ve been providing great ideas, allowing us to enhance our interface design. THANK YOU !

    One small thing:
    When I first ran your sample, I had the same problems from Cyril, the lightbox did not show, and a big “X” appeared in the image control, indicating that the image was not found.

    Then I opened the VCX as a table to see how you embedded the image, and noticed that in the VCX that you provided for this sample, there are some deleted fields. So, in order to ensure this sample would work, I “PACKed” the VCX, and all worked perfectly.

    So, what happened is that as I opened a “clean” instance of VFP, my “SET DELETED” was off. My suggestion is that in the class initialization you SET DELETED to ON, retrieve the embedded image, and then restore it to the original setting.

    Hope this helps !

    Anyway, PACKing your VCX before distribution will solve this too !

    Cheers

    Cesar

    Thanks for that.Zip has been packed and updated.

  • Very nice! thanks!

  • Koen says:

    Thanks for sharing

    You’re welcome.

  • Stefan Stehlik says:

    Hi Bernard

    When you can limit dark region to the form (not the container), you can add image-object on the fly in the LightBoxMsgBox.prg
    <PRE class=codeblock><FONT face=”Courier New” color=#006400>
    *********************************************
    <B>*** LightBoxMsgBox.prg ***</B>
    LPARAMETERS tcMessage, tnType, tcTitleBarText, tnTimeOut
    LOCAL liReturn

    IF TYPE(“_Screen.ActiveForm.Name”) = “C”
      _Screen.ActiveForm.AddObject(“oLightBoxMask”,”cLightBoxMask”)
    ENDIF

    liReturn = IIF(PCOUNT()=4, MESSAGEBOX(tcMessage, tnType, tcTitleBarText, tnTimeout),;
              IIF(PCOUNT()=3, MESSAGEBOX(tcMessage, tnType, tcTitleBarText),;
              IIF(PCOUNT()=2, MESSAGEBOX(tcMessage, tnType),;
                              MESSAGEBOX(tcMessage))))

    IF TYPE(“_Screen.ActiveForm.Name”) = “C”
      _Screen.ActiveForm.RemoveObject(“oLightBoxMask”)
    ENDIF
    RETURN liReturn
    *********************************************
    DEFINE CLASS   cLightBoxMask AS Image
      Picture = “MyMaskFile.png”
      Stretch = 2
      Left = 0
      Top = 0

      PROCEDURE Init()
         THIS.Height = THIS.PARENT.Height
         THIS.Width = THIS.PARENT.Width
         THIS.Visible = .T.
      ENDPROC
    ENDDEFINE
    *********************************************
    *EOF</FONT></PRE>
    Because displayed message is usually strongly related to the underneath form, the LightBox mask should not be so much dark.

    Actually you can do a lot of things on the fly. The class is there for those who want to use it. The source is there for those who want to adapt it. Also your formatting has mucked up the message.

  • MikeS says:

    Nice one Bernard. Thanks for sharing.

    I’ve got one issue with it when placed on a VFP form that contains an ActiveX control (MS webbrowser). The lightbox is not able to capture the contents of the ActiveX, only the hosting VFP form. Is there anyway to have it include the ActiveX content as well?

    Unfortunately that is the problem with Activex and VFP. They insist on appearing on top of all VFP controls. But there are a some things that can be tried.
    1. Hide the web browser – not very good looking
    2. Paint all over the form using GDI+ instead of using a VFP image object. Ask Cesar for that.
    3. Download this file http://siteintranet.qc.ca/vfp/splitter.zip and check out how it is done by Gérald Santerre. That should give you some ideas.
    4. With GDI+x grab an image of the portion of the screen of the current web browser control, hide the Web browser, show an image control with that image from GDI+x and then show the LightBox. Reverse the procedure for removal. Easy Smile <img src=“>

    Check out this link.

  • MikeS says:

    Thanks Bernard. Nice workaround!

  • Mike Yearwood says:

    This lightbox stuff is mildly interesting. The awards thing didn’t seem to indicate it was an outstanding effect.

    “Lightboxes do have downsides, however, and they shouldn’t be used everywhere.

    A lightbox is a blunt instrument that hits users over the head and causes them to stop everything they’re doing. Don’t use them for low-priority items or background information.
    Talk about modal dialog boxes. A lightbox takes that concept to the extreme. (Even though it’s theoretically possible to enable interaction with the dimmed parts of the screen, in practice this just isn’t done because something that’s dimmed should be inactive.)
    Users often have to refer to information on the background display to resolve the situation in the foreground dialog box. If the background is dimmed too much, such information can be hard to read. ”

    However, I just saw an example of this effect which makes incredible sense to me.

    DivX video player can now dim all of the Windows Desktop except the movie. That’s a really useful application of this technique!

Leave a Reply

Your email address will not be published. Required fields are marked *