|
|
READER Q&A
ADVISOR ANSWERS
+ Copy General Fields
+ Store Image Files
+ Windows Colors and Fonts
By Tamar E. Granor, Editor; Ted Roche, Contributing Editor; and Christof Lange, FoxPro Advisor
Copy General Fields
Visual FoxPro 6.0/5.0/3.0, FoxPro 2.x
Q: I'm manipulating General fields, and don't understand how to move pictures into and out of General fields. I can copy a picture from the Clipboard to my table like this:
KEYBOARD "{CTRL+V} {CTRL+W}"
MODIFY GENERAL my_table.picture
But, how can I copy a picture from my_table.picture to the Clipboard, or copy a picture from one table to another?
-- Roland Klingler (via CompuServe)
A: You're on the right track with the code above. With simple bitmaps, you can just reverse the process like this:
KEYBOARD "{CTRL+C}{CTRL+W}"
MODIFY GENERAL my_table.picture
In a quick test, that seemed to work for me. However, the Windows Copy command (Ctrl + C) seems to copy exactly what it sees, whether scaled, distorted, or cropped, into the .BMP format. Since this isn't necessarily the underlying data, you can lose some resolution. In general, the best way to extract a file from a General field is to open the field in a MODIFY GENERAL window, as above, then open the data file in its server program -- PaintBrush, typically for bitmaps -- and finally, save the file from there.
This can be considered both a feature and a detriment. It's a feature for the developer who wants his artwork to remain embedded inside the application. It's a detriment if you're trying to extract the files and don't have, or don't necessarily know, the original server application.
When copying from one table to another, you can manipulate the field data in the same way as other data types. Use the code below to copy a record from one table into another:
SELECT picture from my_table ;
WHERE <you specify which record> ;
INTO CURSOR Temp
INSERT INTO Target_Table VALUES (Temp.picture)
This method retains all the information that was in the original General field, and is probably a better solution.
-- Ted
Store Image Files
Visual FoxPro 6.0/5.0/3.0
Q: I have a table with 1,000 records using about 233KB. When I add a General field and fill it with .JPEG files using APPEND GENERAL... FROM...LINK, the .FPT file grows to 877MB. The size of my pictures totals only 12.6MB. Why does the table become so large, and how can I keep it smaller?
-- S. Sandu (via Advisor.com)
A: General fields have a number of disadvantages in contemporary applications. With the LINK option, you specify that only the link to the .JPEG file is stored in the General field. But that's only half the truth. In fact, besides the file name and some additional information about the application used to display the image, a General field also contains a preview picture. This picture is stored in an uncompressed bitmap format and, therefore, requires a lot of space.
The purpose of this preview image is to display what's in the General field without having to load the application that actually displays it. In the past, when it took a minute or more to load an application like Word or Excel, this preview picture of an OLE document made sense. It let you embed, for example, an Excel chart in a Word document -- Word could display the last version of that spreadsheet in seconds without having to load Excel. When you double-clicked on the spreadsheet to edit it, Excel was automatically loaded. You still had to wait a minute, but not before you really needed Excel. Especially with embedded documents from several server applications, a preview picture was the only way to retain acceptable speed. In addition, General fields tended to cause memo bloat. Every time you double-clicked on the document to edit it and let the server application save the file, a copy of the document and an updated preview image was added to the .FPT file, and the old version was marked as outdated. PACK can compress the file, but youcertainly don't want to pack a table of that size every time you modify a document in a General field.
Another problem is that even though you can easily add a file to a General field, it's difficult to get it back into a file. There are various routines around (in online newsgroups, forums, and Web sites) to extract a .BMP file or a Word document, but each file type and each server application requires its own routine for that. (Jonathan Finch was kind enough to let us publish his program that can extract .BMP, .DOC, .GIF, and .JPG files from a General field and copy them into a file. You'll find GENTOFIL.PRG on this issue's Professional Resource CD. )
This all leads to the recommendation to rarely use General fields. There may be some situations where they're useful, but in my experience, they only make sense when you create them temporarily to include a document in a Visual FoxPro report or to display them on a form.
There are a couple of alternatives, depending on the version of Visual FoxPro you're using and your particular needs. If you want to keep the .JPEG files externally, the easiest solution is to use a character field that holds the file name. To display the file in Visual FoxPro 6.0, add an image controlto the form and put this code into the form's Refresh event:
This.Image.Picture = myTable.ImgPath
ImgPath is the name of the field that holds the path and filename of the .JPEG file. Versions prior to Visual FoxPro 6.0 can't display .JPEG files natively. In which case, you can either use a third-party tool such as Espia (http://www.espia.com/) or LeadTools (http://www.leadtools.com/) that provides ActiveX controls to display an image. You can also use the following approach. In the Load event of the form or the OpenTables event of the data environment in a SCX-based form, create a temporary cursor that has a General field:
Create Cursor curImage( Img G )
Append Blank
Add an OLEBoundControl to the form and set the ControlSource to curImage.Img. In the Refresh event, enter this code:
Append General Img From (myTable.ImgPath)
Many developers choose General fields because they don't want to have the files separate from the table. The user shouldn't be able to break the application by accidentally deleting the image files. In this situation, use a binary memo field instead of a General field. You can use this line to get the file into the memo field:
Append Memo Img From <File> Overwrite
where Img is the name of the binary memo field. In Visual FoxPro 6.0, use an image control to display such a .JPEG file. This requires the following code in the Refresh event of the form:
Local lcFile
* Delete the previous image, if it exists
If File(This.Image.Picture)
Erase (This.Image.Picture)
Endif
* Create a new temporary file on disk
* SYS(2023) returns the current temporary path
lcFile = SYS(2023)+"\"+Sys(3)+".JPG"
Copy Memo myTable.Img to (m.lcFile)
This.Image.Picture = m.lcFile
Using versions prior to Visual FoxPro 6.0, you'll need a temporary General field as described above. In the Refresh event of the OLEBoundControl, put in this code:
Local lcFile
lcFile = SYS(2023)+"\"+Sys(3)+".JPG"
Copy Memo myTable.Img to (m.lcFile)
Append General Img From (m.lcFile)
Erase (m.lcFile)
If your application deals with a lot of image files, it might be faster to keep them in binary memo fields, rather than having them externally as single files. The reason is that Visual FoxPro appears to be more efficient in locating a record in a table than Windows is in locating a file in a directory. After all, a directory doesn't have any indexes, and it doesn't support Rushmore.
-- Christof
Windows Colors and Fonts
Visual FoxPro 6.0/5.0/3.0
Q: Is there a simple way to modify the text attributes for the message in the MessageBox() function? If not, is there any similar function I can use that lets me modify the attributes?
-- Sam Chang (via Advisor.com)
Q: How do I change the background color of a CommandButton? I've heard that it should follow the Windows default environment. Is that true?
-- Donly Wu (via Advisor.com)
A: I've grouped these two questions together, because they raise the same issue about writing applications in a Windows environment. The font used for the MessageBox() function and the BackColor of buttons are both controlled by Windows. More specifically, they're settings over which the user has control through the Windows Display Properties dialog.
An easy way to open that dialog is to right-click on the desktop and choose Properties. For these particular settings, choose the Appearance page. (It's also available through the Display item in the Control Panel.) It's clear how the user can change the MessageBox() font. In the Item dropdown, choose Message Box, and the various font items in the dialog are enabled. The user can choose the font, size, color, and style (bold or italic) of the message in a message box.
Setting the background color of buttons in this dialog is a little more subtle. That color is controlled by the 3-D Objects settings. The user can set a background color and a foreground color, which control the colors of all dialogs in Windows. A button is expected to share its background color with the dialog that contains it. (In fact, the trick that used to give buttons a 3-D appearance is based on the form having the same background color, which isn't quite as visually effective when they're different colors.)
Of course, Visual FoxPro does let you change all kinds of other colors without regard for the Windows settings, so why not these? I don't really have a good answer except to turn the question around. Why are we allowed to change colors and fonts without regard for the users' preferences? The answer is that there are situations where something special is appropriate. For example, to get the user's attention, a particular item might need to be in an extremely large font.
However, this discussion points out that changing BackColor, ForeColor, and the other color properties may cause problems for some users. First, many users set up their own "appearance schemes" and, in fact, Windows includes an entire collection (as well as so-called Desktop Themes, in some versions) for users to choose from. If your application expects the default Windows colors and makes changes accordingly, it's going to stand out for those users, and not in a good way.
Far more important is that some users have visual problems of one kind or another. Both color blindness and visual impairment mean that some users set their machines with very specific color and/or font combinations that enable them to work. Setting custom colors or fonts in your applications is a risky business.
How can you handle this issue in a way that respects the user, but lets you emphasize what you think is important? The answer has two parts. First, wherever possible, use the Windows settings. By default, new forms created in Visual FoxPro 5.0 and later use the Windows 3-D settings. This is controlled by the ColorSource property. The default value is 4-Windows Control Panel (3-D Colors). ColorSource also provides the option of using the Windows Window Colors (5); those are the ones that control documents. Whenever possible, use one of these two settings, and do not directly set any of the color properties.
If you do need to specify special colors in some situations, your best bet is to find out what colors the user's machine is currently set for and then set other colors based on those. You can choose other user color settings that can be assumed to contrast well with the colors in use. For example, the setting for menu text can be assumed to contrast with the setting for the menu itself. If users failed to make them contrast, they're likely to notice it in every application they use, not just yours.
The GetSysColor() API function tells you what the system colors are. To use it, you must first declare it:
DECLARE Integer GetSysColor ;
IN Win32API ;
INTEGER nElement
After you declare it, you can inquire about the color of any individual element—just pass the numbers that identify the elements. Finding out what those numbers are is the hardest part. The documentation for the function (which I found online in the MSDN library) uses a set of named constants and doesn't point to documentation for them. Here are the constants that will most likely interest you:
#DEFINE COLOR_SCROLLBAR 0
#DEFINE COLOR_BACKGROUND 1
#DEFINE COLOR_ACTIVECAPTION 2
#DEFINE COLOR_INACTIVECAPTION 3
#DEFINE COLOR_MENU 4
#DEFINE COLOR_WINDOW 5
#DEFINE COLOR_WINDOWFRAME 6
#DEFINE COLOR_MENUTEXT 7
#DEFINE COLOR_WINDOWTEXT 8
#DEFINE COLOR_CAPTIONTEXT 9
#DEFINE COLOR_ACTIVEBORDER 10
#DEFINE COLOR_INACTIVEBORDER 11
#DEFINE COLOR_APPWORKSPACE 12
#DEFINE COLOR_HIGHLIGHT 13
#DEFINE COLOR_HIGHLIGHTTEXT 14
#DEFINE COLOR_BTNFACE 15
#DEFINE COLOR_BTNSHADOW 16
#DEFINE COLOR_GRAYTEXT 17
#DEFINE COLOR_BTNTEXT 18
#DEFINE COLOR_INACTIVECAPTIONTEXT 19
#DEFINE COLOR_BTNHIGHLIGHT 20
To determine the current background color for buttons, you can call:
nButtonBack = GetSysColor(COLOR_BTNFACE)
To take colors apart into their red, green, and blue values, use the RGBComp() function in the FoxTools library:
SET LIBRARY TO FoxTools ADDITIVE
STORE 0 TO nRed, nGreen, nBlue
RGBComp(nButtonBack, @nRed, @nGreen, @nBlue)
Handling font settings is trickier. Although there are a lot of font and size settings (title bars, menus, message boxes, and so on) available in the Appearance dialog, Windows doesn't provide a way for users to set the default font and size for either dialogs or documents. Perhaps that's because the needs of each application are so different. Your best bet is to respect the user's settings for message boxes and other interface elements, and let the user set fonts and sizes within your application to make it accessible to the broadest range of users.
Finally, to be sure your application isn't making unreasonable assumptions, it's a good idea to test it using several different color schemes. In 16-bit Windows, the Hot Dog Stand scheme was always a good choice for pointing out color problems. That one's gone in 32-bit Windows, but it isn't hard to create your own unusual scheme. In Windows 98, try the Baseball theme -- it's pretty gaudy.
-- Tamar
Editor Tamar E. Granor is an independent consultant specializing in database applications using FoxPro, and a Microsoft Certified Professional. tamar_granor@compuserve.com.
Contributing Editor Ted Roche is a senior consultant at Blackstone Inc. in Waltham, Massachusetts, and a Microsoft Certified Solution Developer. tedroche@compuserve.com.
Christof Lange is the owner of The Foxpert!, a company that specializes in FoxPro development and successfully cooperates with ProLib. He's a speaker at FoxPro User Group meetings, and the author of several articles about FoxPro. ChrisLange@compuserve.com.
Tamar, Ted, and Christof are all Microsoft Support Most Valuable Professionals. Tamar and Ted are the authors of the Hackers Guide to Visual FoxPro 6.0 (Hentzenwerke Publishing, http://www.hentzenwerke.com/) and its predecessor, the Hackers Guide to Visual FoxPro 3.0. Some of the code in ADVISOR Answers is based on the work Tamar and Ted did for the Hackers Guide, which was partially inspired by questions submitted to ADVISOR Answers.
Keyword Tags: Application Design, Database, Database Development, Microsoft, Microsoft FoxPro, Microsoft Visual FoxPro, Programming
ADVISORAMA He has muscles in places where I don't even have places. -- Bob Hope
|
ARTICLE INFO
Print Edition: July 1999, Page 10
FREE ACCESS
|
SUBSCRIPTION STATUSYou are not signed-in. If you are a subscriber to this publication, sign-in above to access locked articles. To subscribe or renew go to www.AdvisorStore.com.
|

Get it all -- every current and past ADVISOR tech/business publication, now all-in-one subscription, with new articles and a huge reference library packed with expert advice, how-to and downloads. Subscribe now to get it all.![]() 
Read the advanced guide to creating custom business database solutions with FileMaker software. Subscribe now to gain access to all the archives and downloads.![]() 
Learn the fundamentals of using FileMaker Pro software. Every issue gives you step-by-step instructions on creating the databases you need. Subscribe now!![]()
![]()
![]()
 ![]()

Submit your tips, techniques and advice and let Advisor promote your business and build your career. Show the world what you know!![]()  ![]()
|
|