Welcome to Foxite.COM Community Weblog Sign in | Join | Help

Bernard Bout

May the Fox be with you...




Embed Your Images

It has always been a problem for me to have to include images for each class as an external file. Not only is file access slow, but VFP has an irritating way of displaying the Hourglass cursor every time a file is accessed from disk. This is especially noticeable in graphical buttons that have a bitmap change for a MouseEnter and MouseLeave event.

 

Well not any more. Using a field in the class – the USER field, I have in one stroke removed both these irritants. Using the method described here, disk reads are eliminated and there is no need to include the bitmaps.

 

Note: This method only works with VFP9 since it uses the PictureVal property to load images. Also this will only work with the IMAGE base class since other objects, while they have a picture property, do not have a PictureVal property.

 

The method is simple. Store the bitmap into the USER field of the image class and at runtime retrieve it and assign the PictureVal property of the image object to it.

 

Let’s start. Create a new class – ImageXML based on the image object. For now, just save it.

 

 

 

I have created a simple Builder to assist in inserting the images. This is included in the download files. Feel free to improve the builder as you see fit.

 

Run the builder and follow the steps 1,2,3.

 

  1. Select the Picture. The image selected is displayed next to the button.
  2. Select the class you just created. The TextBox will display the selected class name.

 

There is a Button with Red writing if you want to clear out the contents of the USER field if there is any other data there. Click this button to clear it out.

 

3. Click the “Insert Image” button and the image is instantly inserted into the USER field of the class. Select other bitmaps (1) and append them (3). When you have inserted your images, close the builder and Browse the class as a table. In the USER field you will find lots of new data. I have used delimiters in the builder <name> and </name>   <picture> and </picture> to separate the images inserted.

 

Please note down the images as you insert them so that you can know what they are later when you want to assign them. Close the class opened earlier as a table.

 

Now open your class as a class and add a new method to it – ProcessImages

Add the following code to the ProcessImages method.

 

* process the images

* open the class as a table

USE (THIS.CLASSLIBRARY) IN 0 ALIAS xClass SHARED

* get the field we want only

SELECT USER FROM xClass WHERE  NOT EMPTY(USER) AND baseclass="image" INTO CURSOR userStr

* store the pictures

LOCAL cPixStr,nPix,cPixname,cPixContents

nPix = 1

cPixStr = ALLTRIM(USERSTR.USER)

* not needed anymore so close them off

USE IN SELECT("userstr")

USE IN SELECT("xClass")

* loop through the data extracting the images

DO WHILE .T.

      cPixname = STREXTRACT(cPixStr,[<name>],[</name>],nPix)

      IF EMPTY(cPixname)

            EXIT

      ENDIF

      cPixcontents = STREXTRACT(cPixStr,[<picture>],[</picture>],nPix)

      * add a property to hold this value

      This.AddProperty("pix"+TRANSFORM(nPix),cPixContents)

      nPix = nPix + 1

ENDDO

 

In the INIT of the class call the above method:

 

This.ProcessImages()

 

The image class is complete.

 

To test the image class, create a new form and add an instance of the ImageXML.bbImage to the form. As you can see from the above code, the images are stored in properties added at runtime, that are named pix1, pix2 etc for however many images you have inserted.

 

So open the INIT of the image object and add this code:

 

* run parent code

DODEFAULT()

 

* assign the PictureVal – pix1 or pix2 or pix3 etc

This.PictureVal = This.Pix1

 

If you are using the image object as a button and want the image to change when the Mouse enters and leaves, then in the MouseEnter add code like this:

 

This.PictureVal = This.pix2

 

And reset it in the mouse leave

 

This.PictureVal = This.pix1

 

That is all that needs to be done. No images to ship and no hourglass to be seen. This method of using images even works at runtime since the VCX is compiled into the exe and can be opened and read like a table.

 

As mentioned the Builder is very simple and can easily be improved. At present, with the sample code supplied, only 1 image class per classlib is supported, but by changing the ProcessImages Code, more than one image object can easily be added to the classlib.

 

Here is the Testform with the Images assigned:

 

and the large image changes as the mouse moves over it:

Published Sunday, February 18, 2007 3:56 AM by bbout
Attachment(s): imagexml.zip

Comments

# re: Embed Your Images @ Sunday, February 18, 2007 3:28 PM

Hi Bernard:

I enjoy your blog ,you do a great job at it!

About your picture management in this article, I think it is not efficient because turns something easy into some complicated. I mean, the process of editing the user field for storing concatenated bitmaps (even with a wizard) for later reading a memo and getting the bitmaps one by one is not an optimal way to do it. The STREXTRACT() function, like AT(), is not optimized for long srings, and each search of a substring do a FULLSCAN from the begining of it, so last elements are slower to find than first elemnts.

I think another way that one can use to accomplish this without editing classes fields and scanning substrings, but using common methods and having the same (may be better) performance:
- Using the idea of pre-loading images in a class for later use (a cache), you can do this using external BMP files and loading just the same way you do in your class, using properties or even a collection for accessing them using a key or index. Remember that when you do an EXE or APP all files are contained in it, even file pictures.
- Later, when you need to use those pictures just get the property or item collection value and assign it to the image control you want.

I think that this have the better of both worlds, the facility of the BMP files and the performance of the preloaded images for not accesing disk every time.

If you make this class an external DLL or EXE library, you can switch libraries with distinct images (like skins).


Best Regards,

Fernando D. Bozzo
Madrid/España

Hi Fernando

As you must realise I already know all about what you are saying and that the EXE will contain the bitmaps. The problem I have found on many an occasion is that I send someone a class and forget to send a bitmap, or in many graphics intensive classes there are numerous bitmaps lying around.

This way, I can embet the bitmaps into the class and just forget about them. Most classes use small bitmaps so speed is not an issue. Besides this is just a technique that can be improved.

The USER field in the class is just that - a field for us to store info and data. I considered storing the bitmaps into properties as well as storing them in dummy methods. However since properties and methods can have their own name, a builder would not be easy to construct given that each person would have their own idea about what to name the property/method.

Just think how you'd use a property e.g. VISIBLE if you were allowed to change it to anything you wanted. You call it one thing, someone else another and there is no consistenncy at all. Hence the reason why I setteled on the USER field for this and many other reasons.

Thanks for your feedback though. I really appreciate it when someone comments.

Bernard

Fernando D. Bozzo

# re: Embed Your Images @ Sunday, February 18, 2007 6:53 PM

That's neat Bernard.  Very cool.

Coming from you, that IS a real compliment. Your TABS for GenscrnX driver was even cooler.

Thanks Steve

Steven Black

# re: Embed Your Images @ Monday, February 19, 2007 11:45 AM

Ok, now is clear what the problem was in first place: the distribution.

Just to add that I've used that user field too to store bitmaps, but with problems loosing them when the class is in a library with other classess and there are changes in those classess.

Regards,

Fernando D. Bozzo
Madrid/Spain

No worries Fernando. I appreciate your comments.

Bernard

Fernando D. Bozzo

New Comments to this post are disabled
Powered by Community Server, by Telligent Systems