<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-30880849</id><updated>2011-05-26T19:40:36.746+02:00</updated><title type='text'>Hans de Groot</title><subtitle type='html'>Mostly about Visual Foxpro...</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://hdegroot.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/30880849/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://hdegroot.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Hans de Groot</name><uri>http://www.blogger.com/profile/06951165924122411855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_hAxQHDMy4bQ/SlSxqsliXkI/AAAAAAAAABI/78WZXTCCkpA/S220/hans100x127.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>13</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-30880849.post-269770012943377843</id><published>2009-05-17T11:24:00.003+02:00</published><updated>2009-05-18T22:30:44.565+02:00</updated><title type='text'>Syntax checking on e-mail addresses</title><content type='html'>You can use the following code to validate e-mail addresses in your Foxpro applications. &lt;br /&gt;&lt;span style="COLOR: rgb(0,0,153);font-family:courier new;font-size:80%;"&gt;&lt;br /&gt;* Procedure validatemail([emailaddress])&lt;br /&gt;&lt;br /&gt;PARAMETERS pEmail&lt;br /&gt;&lt;br /&gt;LOCAL cDomains, cPiece, cMessage, cNum, lDomain, lemailname&lt;br /&gt;&lt;br /&gt;pEmail = LOWER(ALLTRIM(pEmail))&lt;br /&gt;cMessage = ""&lt;br /&gt;lDomain = .t.&lt;br /&gt;lEmailname = .t.&lt;br /&gt;&lt;br /&gt;IF !EMPTY(pEmail)&lt;br /&gt;&lt;br /&gt; cdomains = '"aero", "asia", "biz", "cat", "com", "coop", ' +;&lt;br /&gt;            '"edu", "gov", "info", "int", "jobs", "mil", "mobi", "museum", ' +;&lt;br /&gt;            '"name", "net", "org", "pro", "tel", "travel"'&lt;br /&gt;                       &lt;br /&gt; * some extra checks which are not tackled below&lt;br /&gt; IF ".." $ pemail OR "@." $ pemail OR ".@" $ pemail  &amp;&amp; missing pieces between dots and pigtail&lt;br /&gt;  lEmailname = .f.&lt;br /&gt; ENDIF&lt;br /&gt; IF NOT "@" $ pEmail  &amp;&amp; no pigtail&lt;br /&gt;  lEmailname = .f.&lt;br /&gt; ENDIF &lt;br /&gt; IF OCCURS("@", pemail) &gt; 1  &amp;&amp; multiple pigtails&lt;br /&gt;  lEmailname = .f.&lt;br /&gt; ENDIF &lt;br /&gt;&lt;br /&gt; * check the emailname &lt;br /&gt; cPiece = LEFT(pEmail, AT("@", pEmail)-1)&lt;br /&gt; IF EMPTY(cPiece)&lt;br /&gt;  lEmailname = .f.&lt;br /&gt; ELSE &lt;br /&gt;  FOR i = 1 TO LEN(cPiece)&lt;br /&gt;   cNum = ASC(SUBSTR(cPiece,i,1))&lt;br /&gt;   * A to Z, 0 to 9, ! to /&lt;br /&gt;   IF between(cNum, 97,122) OR;&lt;br /&gt;      between(cNum, 48,57) OR;&lt;br /&gt;      between(cNum, 33,47)&lt;br /&gt;   ELSE&lt;br /&gt;    lEmailname = .f.&lt;br /&gt;   ENDIF&lt;br /&gt;  ENDFOR&lt;br /&gt; ENDIF&lt;br /&gt; &lt;br /&gt; * check the domain name&lt;br /&gt; cPiece = SUBSTR(pEmail, RAT("@", pEmail)+1)          &lt;br /&gt; IF EMPTY(cPiece)  &amp;&amp; empty&lt;br /&gt;  lDomain = .f.&lt;br /&gt; ELSE&lt;br /&gt;  IF LEN(cPiece) &lt; 4  &amp;&amp; domain name to short&lt;br /&gt;   lDomain = .f.&lt;br /&gt;  ENDIF&lt;br /&gt;&lt;br /&gt;  cPiece = SUBSTR(pEmail, RAT(".", pEmail)+1)          &lt;br /&gt;  IF LEN(cPiece) &lt; 2  &amp;&amp; part after the last dot to short&lt;br /&gt;   lDomain = .f.&lt;br /&gt;  ENDIF&lt;br /&gt;  IF LEFT(pEmail,1) $ "." &amp;&amp; begins with a dot&lt;br /&gt;   lDomain = .f.&lt;br /&gt;  ENDIF&lt;br /&gt;&lt;br /&gt;  FOR i = 1 TO LEN(cPiece)&lt;br /&gt;   cNum = ASC(SUBSTR(cPiece,i,1))&lt;br /&gt;   * A to Z, 0 to 9, ! to /&lt;br /&gt;   IF between(cNum, 97,122) OR;&lt;br /&gt;      between(cNum, 48,57) OR;&lt;br /&gt;      between(cNum, 33,47)&lt;br /&gt;   ELSE&lt;br /&gt;    lDomain = .f.&lt;br /&gt;   ENDIF&lt;br /&gt;  ENDFOR&lt;br /&gt;&lt;br /&gt;  IF LEN(cPiece) &gt; 2  &amp;&amp; top level domain&lt;br /&gt;   IF NOT '"' + cPiece + '"' $ cdomains &amp;&amp; no top level domain&lt;br /&gt;    lDomain = .f.&lt;br /&gt;   ENDIF&lt;br /&gt;  ELSE&lt;br /&gt;   * If you have a list with all the country codes, you could check them here...&lt;br /&gt;  ENDIF&lt;br /&gt; ENDIF&lt;br /&gt;ENDIF&lt;br /&gt; &lt;br /&gt;RETURN (lEmailname = .T. AND lDomain = .T.)  &lt;br /&gt;&lt;br /&gt;&lt;/span style="font-size:80%;"&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30880849-269770012943377843?l=hdegroot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hdegroot.blogspot.com/feeds/269770012943377843/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=30880849&amp;postID=269770012943377843' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/30880849/posts/default/269770012943377843'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/30880849/posts/default/269770012943377843'/><link rel='alternate' type='text/html' href='http://hdegroot.blogspot.com/2009/05/syntax-checking-on-e-mail-addresses.html' title='Syntax checking on e-mail addresses'/><author><name>Hans de Groot</name><uri>http://www.blogger.com/profile/06951165924122411855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_hAxQHDMy4bQ/SlSxqsliXkI/AAAAAAAAABI/78WZXTCCkpA/S220/hans100x127.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-30880849.post-6560081229294376102</id><published>2009-03-07T08:04:00.006+01:00</published><updated>2009-03-07T11:54:51.864+01:00</updated><title type='text'>An application-wide hourglass</title><content type='html'>When your users are waiting for your application to complete some task, it's nice to show them the hourglass mousepointer as an indication. You can easily set the mousepointer property of the active form, but when the user moves the mouse outside of it, the mousepointer changes to the arrowhead again and that's not how it should be. &lt;br /&gt;The following code changes the mousepointer for all the forms in your application. &lt;br /&gt;Put the code in a .PRG file and (very important!) name it MAUSER, because that was what Richard and I named it originally. &lt;br /&gt;The reason for that is, that at the moment we were thinking about how to name this function, our friend Maurits walked in the room and 'Maus' is what we call him for short. Also 'maus' is the German word for mouse.&lt;br /&gt;&lt;br /&gt;Activating and deactivating the hourglass is as simple as putting =MAUSER(.T.) and =MAUSER(.F.) around the piece of code that takes a while to execute.&lt;br /&gt;&lt;br /&gt;&lt;span style="COLOR: rgb(0,0,153);font-family:courier new;font-size:80%;"&gt;&lt;br /&gt;PARAMETERS lZetAan&lt;br /&gt;&lt;br /&gt;LOCAL nFormTeller&lt;br /&gt;&lt;br /&gt;FOR nFormTeller = 1 TO _Screen.FormCount&lt;br /&gt; _Screen.Forms(nFormTeller).SetAll("MousePointer",IIF(lZetAan,11,0))&lt;br /&gt; _Screen.Forms(nFormTeller).MousePointer = IIF(lZetAan,11,0)&lt;br /&gt;NEXT&lt;br /&gt;_Screen.SetAll("MousePointer",IIF(lZetAan,11,0))&lt;br /&gt;&lt;br /&gt;_Screen.MousePointer = IIF(lZetAan,11,0)&lt;br /&gt;IF TYPE("_Screen.Activeform.Name") = "C"&lt;br /&gt; _Screen.Activeform.SetAll("MousePointer",IIF(lZetAan,11,0))&lt;br /&gt;ENDIF&lt;br /&gt;&lt;/span style="font-size:80%;"&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30880849-6560081229294376102?l=hdegroot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hdegroot.blogspot.com/feeds/6560081229294376102/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=30880849&amp;postID=6560081229294376102' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/30880849/posts/default/6560081229294376102'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/30880849/posts/default/6560081229294376102'/><link rel='alternate' type='text/html' href='http://hdegroot.blogspot.com/2009/03/application-wide-hourglass.html' title='An application-wide hourglass'/><author><name>Hans de Groot</name><uri>http://www.blogger.com/profile/06951165924122411855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_hAxQHDMy4bQ/SlSxqsliXkI/AAAAAAAAABI/78WZXTCCkpA/S220/hans100x127.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-30880849.post-7562667788510116227</id><published>2008-08-07T08:10:00.007+02:00</published><updated>2008-08-07T08:27:59.833+02:00</updated><title type='text'>Can you put a file in the desired location?</title><content type='html'>When you want to put a file in a certain location, you may want to check if it is possible to write to that location. You might not have write permission, the location might not exist or a file with the same name allready exists and cannot be overwritten because it is in use. With the code below, you can check this out:&lt;br /&gt;&lt;span style="COLOR: rgb(0,0,153);font-family:courier new;font-size:80%;"&gt;&lt;br /&gt;* FUNCTION FILEOVERWRITE()&lt;br /&gt;&lt;br /&gt;PARAMETERS cGo&lt;br /&gt;&lt;br /&gt;fhandle =FCREATE(cGo) &lt;br /&gt;IF fhandle &gt; -1&lt;br /&gt; =FCLOSE(fhandle)&lt;br /&gt; DELE FILE (cGo)&lt;br /&gt; RETURN .T.&lt;br /&gt;ELSE&lt;br /&gt; RETURN .F.&lt;br /&gt;ENDIF&lt;br /&gt;&lt;/span style="font-size:80%;"&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30880849-7562667788510116227?l=hdegroot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hdegroot.blogspot.com/feeds/7562667788510116227/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=30880849&amp;postID=7562667788510116227' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/30880849/posts/default/7562667788510116227'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/30880849/posts/default/7562667788510116227'/><link rel='alternate' type='text/html' href='http://hdegroot.blogspot.com/2008/08/can-you-put-file-in-desired-location.html' title='Can you put a file in the desired location?'/><author><name>Hans de Groot</name><uri>http://www.blogger.com/profile/06951165924122411855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_hAxQHDMy4bQ/SlSxqsliXkI/AAAAAAAAABI/78WZXTCCkpA/S220/hans100x127.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-30880849.post-2746183671594417546</id><published>2008-08-01T17:41:00.003+02:00</published><updated>2008-08-01T17:52:03.506+02:00</updated><title type='text'>Function that returns a part of a comma-separated string</title><content type='html'>Whenever you need to to handle comma-separated string, you might want to check the function below, which makes use of VFP's ALINES() function to return a certain value in the string.&lt;br /&gt;&lt;br /&gt;&lt;span style="COLOR: rgb(0,0,153);font-family:courier new;font-size:80%;"&gt;&lt;br /&gt;* Parameters: String (character) , which part (numeric), delimiter (character) &lt;br /&gt;PARAMETERS cCsv, nPart, pdelimiter&lt;br /&gt;&lt;br /&gt;IF PCOUNT() &lt; 3&lt;br /&gt; pDelimiter = ","&lt;br /&gt;ENDIF &lt;br /&gt;&lt;br /&gt;cCsv = STRTRAN(cCsv, pDelimiter, " "+CHR(13) )&lt;br /&gt;&lt;br /&gt;ALINES(aCsv, cCsv , .T.)&lt;br /&gt;&lt;br /&gt;* When array element 1 = .False. =&gt; return ""&lt;br /&gt;* When the number of array elements &lt; nPart =&gt; return ""&lt;br /&gt;* Otherwise, return the piece of the string &lt;br /&gt;&lt;br /&gt;RETURN IIF(  TYPE( "aCsv[1]" ) = "L" , "", IIF( ALEN(aCsv,1) &lt; nPart , "", aCsv[nPart] ) )&lt;br /&gt;&lt;/span style="font-size:80%;"&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30880849-2746183671594417546?l=hdegroot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hdegroot.blogspot.com/feeds/2746183671594417546/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=30880849&amp;postID=2746183671594417546' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/30880849/posts/default/2746183671594417546'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/30880849/posts/default/2746183671594417546'/><link rel='alternate' type='text/html' href='http://hdegroot.blogspot.com/2008/08/function-that-returns-part-of-comma.html' title='Function that returns a part of a comma-separated string'/><author><name>Hans de Groot</name><uri>http://www.blogger.com/profile/06951165924122411855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_hAxQHDMy4bQ/SlSxqsliXkI/AAAAAAAAABI/78WZXTCCkpA/S220/hans100x127.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-30880849.post-7645027771166991948</id><published>2008-07-28T21:11:00.010+02:00</published><updated>2008-07-28T21:51:51.730+02:00</updated><title type='text'>Resize or reposition a desktop form to fit the Windows desktop</title><content type='html'>In your VFP application, you want your users to have the application form re-appear as it was left behind the last time. So, you store the screen coordinates (in your apps mechanism that saves the application settings) and restore the form to the saved coordinates, the next time it is run.&lt;br /&gt;But in the mean time, the user may have altered the screen resolution, changed to a p.c. with a different screen resolution or moved/resized the Windows startbar.&lt;br /&gt;&lt;br /&gt;I these scenario's, your application form may not fit in the Windows desktop anymore.&lt;br /&gt;Below, you find the code of SETFORMSIZE.PRG, which repositions the form to fit the desktop again.&lt;br /&gt;&lt;br /&gt;To test it: &lt;br /&gt;- create a form with the desktop property to .True.&lt;br /&gt;- Put this code in the load method of the form:&lt;span style="COLOR: rgb(0,0,153);font-family:courier new;font-size:80%;"&gt;&lt;br /&gt;This.Top = -100&lt;br /&gt;This.Left = -100&lt;br /&gt;This.Width = 100000&lt;br /&gt;This.Height = 100000&lt;br /&gt;DO SETFORMSIZE WITH This&lt;/span style="font-size:80%;"&gt;&lt;br /&gt;- Run the form&lt;br /&gt;&lt;br /&gt;&lt;span style="COLOR: rgb(0,0,153);font-family:courier new;font-size:80%;"&gt;&lt;br /&gt;************************************************************************&lt;br /&gt;* SETFORMSIZE.PRG                                                      *&lt;br /&gt;************************************************************************&lt;br /&gt;PARAMETERS oForm&lt;br /&gt;&lt;br /&gt;LOCAL nWinHeight, nWinWidth, nCorrection&lt;br /&gt;&lt;br /&gt;* Width en height of screenspace minus space occuped by the startmenu bar&lt;br /&gt;* wherever that is placed or whatever size it is&lt;br /&gt;nWinHeight = SYSMETRIC(22)&lt;br /&gt;nWinWidth  = SYSMETRIC(21)&lt;br /&gt;nCorrection = sysmetric(3)*2&lt;br /&gt;&lt;br /&gt;* First: check if the form is off screen above and to the left&lt;br /&gt;IF oForm.Left &lt; 0&lt;br /&gt; oForm.Left = 0&lt;br /&gt;ENDIF&lt;br /&gt;IF oForm.Top &lt; 0&lt;br /&gt; oForm.Top = 0&lt;br /&gt;ENDIF&lt;br /&gt;&lt;br /&gt;* Next: check if the form is to high or wide to fit in the screen&lt;br /&gt;IF (oForm.Top + oForm.Height) &gt; nWinHeight  &amp;&amp; Oh Oh, Formheight beyond screen&lt;br /&gt; nHowMuch = (oForm.Top + oForm.Height ) - nWinHeight&lt;br /&gt; IF nHowMuch &gt; oForm.Top &amp;&amp; Oh oh, form does not fit in the screen&lt;br /&gt;  IF oForm.MinHeight &gt;= (nWinHeight - oForm.Height )  &lt;br /&gt;   oForm.Height = nWinHeight - nCorrection&lt;br /&gt;  ENDIF&lt;br /&gt;&lt;br /&gt;  nNewTop = 0&lt;br /&gt; ELSE&lt;br /&gt;  nNewTop = (oForm.Top - nHowMuch) - nCorrection &lt;br /&gt; ENDIF &lt;br /&gt;ELSE&lt;br /&gt; nNewTop = oForm.Top&lt;br /&gt;ENDIF&lt;br /&gt;IF (oForm.Left + oForm.Width) &gt; nWinWidth  &amp;&amp; Oh Oh, Formwidth beyond screen&lt;br /&gt; nHowMuch = (oForm.Left + oForm.Width ) - nWinWidth&lt;br /&gt; IF nHowMuch &gt; oForm.Left &amp;&amp; Oh oh, form does not fit in the screen&lt;br /&gt;  IF oForm.MinWidth &gt;= (nWinWidth - oForm.Width )  &lt;br /&gt;   oForm.Width = nWinWidth - nCorrection&lt;br /&gt;  ENDIF&lt;br /&gt;  nNewLeft = 0&lt;br /&gt; ELSE&lt;br /&gt;  nNewLeft = (oForm.Left - nHowMuch) - nCorrection&lt;br /&gt; ENDIF &lt;br /&gt;ELSE&lt;br /&gt; nNewLeft = oForm.Left&lt;br /&gt;ENDIF&lt;br /&gt;&lt;br /&gt;oForm.Left = nNewLeft&lt;br /&gt;oForm.Top = nNewTop&lt;br /&gt;&lt;/span style="font-size:80%;"&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30880849-7645027771166991948?l=hdegroot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hdegroot.blogspot.com/feeds/7645027771166991948/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=30880849&amp;postID=7645027771166991948' title='88 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/30880849/posts/default/7645027771166991948'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/30880849/posts/default/7645027771166991948'/><link rel='alternate' type='text/html' href='http://hdegroot.blogspot.com/2008/07/resize-or-reposition-desktop-form-to.html' title='Resize or reposition a desktop form to fit the Windows desktop'/><author><name>Hans de Groot</name><uri>http://www.blogger.com/profile/06951165924122411855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_hAxQHDMy4bQ/SlSxqsliXkI/AAAAAAAAABI/78WZXTCCkpA/S220/hans100x127.jpg'/></author><thr:total>88</thr:total></entry><entry><id>tag:blogger.com,1999:blog-30880849.post-6636638278982360380</id><published>2007-07-26T07:43:00.001+02:00</published><updated>2007-07-26T08:04:38.536+02:00</updated><title type='text'>Is MS Office installed on a computer?</title><content type='html'>There are more ways to detect if MS Excel, Outlook or Word is installed on a computer. One way is, to look it up in the Window registry.&lt;br /&gt;The following code does exactly that.&lt;br /&gt;&lt;span style="COLOR: rgb(0,0,153);font-family:courier new;font-size:80%;"&gt;&lt;br /&gt;* Code that shows if Outlook, Word and Excel are installed:&lt;br /&gt;&lt;br /&gt;ckey = "Software\Microsoft\Windows\CurrentVersion\App Paths\outlook.exe"&lt;br /&gt;OutlookExists = readregstring(-2147483646, ckey, "path")&lt;br /&gt;&lt;br /&gt;ckey = "Software\Microsoft\Windows\CurrentVersion\App Paths\winword.exe"&lt;br /&gt;WinWordExists = readregstring(-2147483646, ckey, "path")&lt;br /&gt;&lt;br /&gt;ckey = "Software\Microsoft\Windows\CurrentVersion\App Paths\excel.exe"&lt;br /&gt;ExcelExists = readregstring(-2147483646, ckey, "path")&lt;br /&gt;&lt;br /&gt;? !EMPTY(NVL(OutlookExists,""))&lt;br /&gt;? !EMPTY(NVL(WinWordExists,""))&lt;br /&gt;? !EMPTY(NVL(ExcelExists,""))&lt;br /&gt;&lt;/span style="font-size:80%;"&gt;&lt;br /&gt;The code makes use of a function called 'readregstring' That function is:&lt;br /&gt;&lt;span style="COLOR: rgb(0,0,153);font-family:courier new;font-size:80%;"&gt;&lt;br /&gt;***----------------------------------------------------------------------&lt;br /&gt;***  Function: Reads a string value from the registry.&lt;br /&gt;***      Pass: tnHKEY    -  HKEY value (in CGIServ.h)&lt;br /&gt;***            tcSubkey  -  The Registry subkey value&lt;br /&gt;***            tcEntry   -  The actual Key to retrieve&lt;br /&gt;***    Return: Registry String or .NULL. on error&lt;br /&gt;***----------------------------------------------------------------------&lt;br /&gt;LPARAMETERS tnHKey, tcSubkey, tcEntry&lt;br /&gt;LOCAL lnRegHandle, lnResult, lnSize, lcDataBuffer, tnType&lt;br /&gt;&lt;br /&gt;tnHKey=IIF(type("tnHKey")="N",tnHKey,This.HKEY_LOCAL_MACHINE)&lt;br /&gt;&lt;br /&gt;lnRegHandle=0&lt;br /&gt;&lt;br /&gt;DO DeclareInit   &amp;&amp; Declare WinAPI function. You only have to do this once.&lt;br /&gt;        &lt;br /&gt;*** Open the registry key&lt;br /&gt;lnResult=RegOpenKey(tnHKey,tcSubKey,@lnRegHandle)&lt;br /&gt;IF lnResult # 0&lt;br /&gt;   RETURN .NULL.&lt;br /&gt;ENDIF   &lt;br /&gt;&lt;br /&gt;*** Need to define here specifically for Return Type&lt;br /&gt;*** for lpdData parameter or VFP will choke.&lt;br /&gt;*** Here it's STRING.&lt;br /&gt;DECLARE INTEGER RegQueryValueEx ;&lt;br /&gt;        IN Win32API AS RegQueryString;&lt;br /&gt;        INTEGER nHKey,;&lt;br /&gt;        STRING lpszValueName,;&lt;br /&gt;        INTEGER dwReserved,;&lt;br /&gt;        INTEGER @lpdwType,;&lt;br /&gt;        STRING @lpbData,;&lt;br /&gt;        INTEGER @lpcbData&lt;br /&gt;&lt;br /&gt;*** Return buffer to receive value&lt;br /&gt;lcDataBuffer=space(256)&lt;br /&gt;lnSize=LEN(lcDataBuffer)&lt;br /&gt;lnType=0&lt;br /&gt;&lt;br /&gt;lnResult=RegQueryString(lnRegHandle,tcEntry,0,@lnType,;&lt;br /&gt;                         @lcDataBuffer,@lnSize)&lt;br /&gt;&lt;br /&gt;=RegCloseKey(lnRegHandle)&lt;br /&gt;&lt;br /&gt;IF lnResult # 0&lt;br /&gt;   RETURN .NULL.&lt;br /&gt;ENDIF   &lt;br /&gt;&lt;br /&gt;IF lnSize&lt;2&lt;br /&gt;   RETURN ""&lt;br /&gt;ENDIF&lt;br /&gt;   &lt;br /&gt;*** Return string based on length returned&lt;br /&gt;RETURN SUBSTR(lcDataBuffer,1,lnSize-1)&lt;br /&gt;&lt;/span style="font-size:80%;"&gt;&lt;br /&gt;And the DeclareInit function that is called:&lt;br /&gt;&lt;span style="COLOR: rgb(0,0,153);font-family:courier new;font-size:80%;"&gt;&lt;br /&gt;*** Open a registry key&lt;br /&gt;DECLARE INTEGER RegOpenKey ;&lt;br /&gt;        IN Win32API ;&lt;br /&gt;        INTEGER nHKey,;&lt;br /&gt;        STRING cSubKey,;&lt;br /&gt;        INTEGER @nHandle&lt;br /&gt;        &lt;br /&gt;*** Close an open registry key&lt;br /&gt;DECLARE Integer RegCloseKey ;&lt;br /&gt;        IN Win32API ;&lt;br /&gt;        INTEGER nHKey&lt;br /&gt;&lt;/span style="font-size:80%;"&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30880849-6636638278982360380?l=hdegroot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hdegroot.blogspot.com/feeds/6636638278982360380/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=30880849&amp;postID=6636638278982360380' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/30880849/posts/default/6636638278982360380'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/30880849/posts/default/6636638278982360380'/><link rel='alternate' type='text/html' href='http://hdegroot.blogspot.com/2007/07/is-ms-office-installed-on-computer.html' title='Is MS Office installed on a computer?'/><author><name>Hans de Groot</name><uri>http://www.blogger.com/profile/06951165924122411855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_hAxQHDMy4bQ/SlSxqsliXkI/AAAAAAAAABI/78WZXTCCkpA/S220/hans100x127.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-30880849.post-6035787904628035786</id><published>2007-06-29T11:39:00.000+02:00</published><updated>2007-07-26T08:06:10.127+02:00</updated><title type='text'>Importing an Excel spreadsheet in VFP using Excel</title><content type='html'>De native IMPORT function of Visual Foxpro doesn't allways do a good yob. For example, sometimes it converts numbers to date values (01-01-1900). &lt;br /&gt;The code below uses office automation to let Excel itself export the spreadsheet to dBase format. Also, you don't have to know in which version of Excel the spreadsheet is created, like you have to with the IMPORT function.&lt;br /&gt;&lt;br /&gt;The code does not work with Excel 2007, because Microsoft decided to say bye bye to the dBase export filters.&lt;br /&gt;&lt;br /&gt;Run the .PRG file like:&lt;br /&gt;&lt;span style="COLOR: rgb(0,0,153);font-family:courier new;font-size:80%;"&gt;&lt;br /&gt;DO XLS2DBF WITH 'MySpreadsheet.xls', 'MyTable.dbf'&lt;br /&gt;&lt;br /&gt;* XLS2DBF.PRG&lt;br /&gt;*&lt;br /&gt;* Function accepts 2 parameters&lt;br /&gt;* 1) cSheet is the Excel sheet that is to be exported&lt;br /&gt;* 2) cExportFile is the filename of the exportfile&lt;br /&gt;&lt;br /&gt;PARAMETERS cSheet, cExportFile&lt;br /&gt;&lt;br /&gt;IF PCOUNT() = 1&lt;br /&gt; * Create a temp export file&lt;br /&gt; cExportFile = SYS(2023) + "\" + SYS(3) + ".tmp"&lt;br /&gt;ENDIF &lt;br /&gt;&lt;br /&gt;LOCAL lErrorCatched, oExcelWorkbook, nFileFormat&lt;br /&gt;&lt;br /&gt;nFileFormat = 11  &amp;&amp; Excel Saveas constant for dBase IV format. Not available in Excel 2007 though...&lt;br /&gt;lErrorCatched = .F.&lt;br /&gt;&lt;br /&gt;* Can we get to Excel or what?&lt;br /&gt;TRY&lt;br /&gt; oExcelObject   = CREATEOBJECT('Excel.Application')                                &lt;br /&gt;CATCH&lt;br /&gt; lErrorCatched=.T.&lt;br /&gt;ENDTRY &lt;br /&gt;&lt;br /&gt;IF lErrorCatched&lt;br /&gt; RETURN .F.&lt;br /&gt;ELSE&lt;br /&gt;&lt;br /&gt;oExcelWorkbook = oExcelObject.Application.Workbooks.Open(cSheet)&lt;br /&gt;&lt;br /&gt;* When columns in Excel are to small to show all the data, Excel also cuts them off when exporting!&lt;br /&gt;* The code below formats the columns to be wide enough...&lt;br /&gt;oExcelObject.Cells.Select&lt;br /&gt;oExcelObject.Selection.Font.Size = 11  &amp;&amp; dBase IV&lt;br /&gt;oExcelObject.Selection.Columns.AutoFit&lt;br /&gt;oExcelObject.Selection.Font.Size = 8&lt;br /&gt;&lt;br /&gt;oExcelObject.cells(1).select  &amp;&amp; makes sure the whole sheet is exported and not some selected range (or whatever goes wrong with that from time to time...)&lt;br /&gt;oExcelObject.DisplayAlerts = .F. &amp;&amp; prevents overwrite message&lt;br /&gt;oExcelWorkbook.SaveAs(cExportFile, nFileFormat)&lt;br /&gt;oExcelWorkbook.close&lt;br /&gt;&lt;br /&gt;* When opening a .DBF file created by Excel, there is no codepage&lt;br /&gt;* VFP opens up the codepage dialog in order to choose a codepage, but we don't want that&lt;br /&gt;* SET CPDIALOG OFF won;t help, because then there stil is no codepage for the .DBF file&lt;br /&gt;* Luckily, VFP provides CPZERO.PRG, with can update a .DBF with a codepage &lt;br /&gt;* You could do: DO CPZERO WITH cExportFile, 850&lt;br /&gt;* But instead, the code below is a little piece of the CPZERO code that does the job, so we don't&lt;br /&gt;* have to include CPZERO.PRG itself.&lt;br /&gt;LOCAL varcpbyte, varfp_in, varbuf&lt;br /&gt;varcpbyte = 2&lt;br /&gt;varfp_in = FOPEN(cExportFile,2)&lt;br /&gt;IF varfp_in &gt; 0&lt;br /&gt; * First check that we have a FoxPro table...&lt;br /&gt; varbuf=FREAD(varfp_in,32)&lt;br /&gt; IF (SUBSTR(varbuf,1,1) = CHR(139) OR SUBSTR(varbuf,1,1) = CHR(203);&lt;br /&gt;   OR SUBSTR(varbuf,31,1) != CHR(0) OR SUBSTR(varbuf,32,1) != CHR(0))&lt;br /&gt;  =fclose(varfp_in)&lt;br /&gt;  RETURN .F.&lt;br /&gt; ELSE&lt;br /&gt;  * now poke the codepage id into byte 29&lt;br /&gt;  =FSEEK(varfp_in,29)&lt;br /&gt;  =FWRITE(varfp_in,CHR(varcpbyte)) &lt;br /&gt;  =FCLOSE(varfp_in)&lt;br /&gt; ENDIF&lt;br /&gt;ELSE&lt;br /&gt; RETURN .F.&lt;br /&gt;ENDIF&lt;br /&gt;&lt;br /&gt;* If no exportfile is specified, open the data as a temporary table to undertake further action&lt;br /&gt;IF PCOUNT() = 1&lt;br /&gt; cAlias = "C"+SYS(3)&lt;br /&gt; USE (cExportFile) IN 0 ALIAS (cAlias)&lt;br /&gt;* BROWSE NORMAL NOWAIT &amp;&amp; if you want&lt;br /&gt;ENDIF&lt;br /&gt;&lt;br /&gt;* clean up Excel object&lt;br /&gt;oExcelObject = .NULL.&lt;br /&gt;RELEASE oExcelObject&lt;br /&gt;&lt;/span style="font-size:80%;"&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30880849-6035787904628035786?l=hdegroot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hdegroot.blogspot.com/feeds/6035787904628035786/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=30880849&amp;postID=6035787904628035786' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/30880849/posts/default/6035787904628035786'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/30880849/posts/default/6035787904628035786'/><link rel='alternate' type='text/html' href='http://hdegroot.blogspot.com/2007/06/importing-excel-spreadsheet-in-vfp.html' title='Importing an Excel spreadsheet in VFP using Excel'/><author><name>Hans de Groot</name><uri>http://www.blogger.com/profile/06951165924122411855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_hAxQHDMy4bQ/SlSxqsliXkI/AAAAAAAAABI/78WZXTCCkpA/S220/hans100x127.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-30880849.post-1824241345405945638</id><published>2006-10-01T20:09:00.000+02:00</published><updated>2006-10-01T20:16:50.236+02:00</updated><title type='text'>Listgrid - update 3</title><content type='html'>In this third update of the listgrid control, it is possible to change the grid's record source at run time. There is a new 'Open file' button in the example form that shows how.&lt;br /&gt;&lt;br /&gt;Further, to solve the second issue in the post of july 30th, the width of the rightmost column in the grid is now changed to span the gap that normally appears when the total with of the visible columns are smaller than the grid's width. There is a new method &lt;em&gt;Setrightmostcolumnwidth&lt;/em&gt; that takes care of this.&lt;br /&gt;&lt;br /&gt;An updated download is available &lt;a href="http://www.datastudio.nl/download/foxproexamples/listgrid.zip"&gt;&lt;span style="FONT-WEIGHT: bold"&gt;here&lt;/span&gt;&lt;/a&gt; (ZIP compressed file, 45 kb).&lt;br /&gt;&lt;br /&gt;For more info about the Listgrid control, see the original post of July 16.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30880849-1824241345405945638?l=hdegroot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hdegroot.blogspot.com/feeds/1824241345405945638/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=30880849&amp;postID=1824241345405945638' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/30880849/posts/default/1824241345405945638'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/30880849/posts/default/1824241345405945638'/><link rel='alternate' type='text/html' href='http://hdegroot.blogspot.com/2006/10/listgrid-update-3.html' title='Listgrid - update 3'/><author><name>Hans de Groot</name><uri>http://www.blogger.com/profile/06951165924122411855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_hAxQHDMy4bQ/SlSxqsliXkI/AAAAAAAAABI/78WZXTCCkpA/S220/hans100x127.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-30880849.post-6928843019803174064</id><published>2006-09-29T18:47:00.000+02:00</published><updated>2006-09-29T18:58:08.028+02:00</updated><title type='text'>A resize grip on a Foxpro form</title><content type='html'>As a visual clue that a form can be resized, many forms have a 'resize grip' in the lower right corner. Visual Foxpro does not have native support for showing a resize grip on a form. But that won't stop us, we can make our own!&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.datastudio.nl/download/foxproexamples/resizer.zip"&gt;Over here&lt;/a&gt; you can download a zip file containing a resizer class. It's based on a container class and constructs it's own grip shape (Windows XP style). Just drop the class on a form and add  &lt;em&gt;This.resizer1.resize&lt;/em&gt; to the forms resize method. An example form is also included, which looks like this:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger2/5201/3769/1600/resizer.gif"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://photos1.blogger.com/blogger2/5201/3769/320/resizer.gif" alt="" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30880849-6928843019803174064?l=hdegroot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hdegroot.blogspot.com/feeds/6928843019803174064/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=30880849&amp;postID=6928843019803174064' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/30880849/posts/default/6928843019803174064'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/30880849/posts/default/6928843019803174064'/><link rel='alternate' type='text/html' href='http://hdegroot.blogspot.com/2006/09/resize-grip-on-foxpro-form.html' title='A resize grip on a Foxpro form'/><author><name>Hans de Groot</name><uri>http://www.blogger.com/profile/06951165924122411855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_hAxQHDMy4bQ/SlSxqsliXkI/AAAAAAAAABI/78WZXTCCkpA/S220/hans100x127.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-30880849.post-6490858205554299203</id><published>2006-09-02T10:56:00.000+02:00</published><updated>2006-09-02T11:14:33.409+02:00</updated><title type='text'>Images in a VFP grid class</title><content type='html'>In the listgrid class in this blog, it is possible to have different images in the cells of the same column in a grid. This is done using the DynamicCurrentControl feature and works great if there are only a few images.&lt;br /&gt;When you have a lot of images to show, it seems like a bad idea to add even so much image controls to the grid column.&lt;br /&gt;Luckily, there is another way to do the same. I found out about this &lt;a href="http://www.sweetpotatosoftware.com/SPSBlog/PermaLink,guid,878c1b11-1770-405c-92ea-cdbe2c838dfa.aspx"target="_blank"&gt;here&lt;/a&gt; while working on the listgrid class. It works by creating a container class which is used as the control for the column. In the container class itself, you create an access method for the backstyle property of the container (open the class, go to the &lt;em&gt;Class&lt;/em&gt; pad in the Foxpro menu, select &lt;em&gt;Edit property/method&lt;/em&gt; and check the &lt;em&gt;Access Method&lt;/em&gt; for the backstyle.&lt;br /&gt;Then, in the access_method itself, you put code like &lt;em&gt;This.picture = Mytable.Image&lt;/em&gt;, where Image is a text field in Mytable used as the grid recordsource. The text field contains the names of the images to use, which can be found on disk along the VFP path.&lt;br /&gt;&lt;br /&gt;You can download an example &lt;a href="http://www.datastudio.nl/download/foxproexamples/ImagesInGridExample.zip"&gt;here&lt;/a&gt; as a zip compressed file (9.6 Kb). Run the example form and look at the code in the example class. This is how it looks:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://photos1.blogger.com/blogger2/5201/3769/1600/ImagesInGrid.1.gif"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://photos1.blogger.com/blogger2/5201/3769/320/ImagesInGrid.gif" border="0" alt="" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30880849-6490858205554299203?l=hdegroot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hdegroot.blogspot.com/feeds/6490858205554299203/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=30880849&amp;postID=6490858205554299203' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/30880849/posts/default/6490858205554299203'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/30880849/posts/default/6490858205554299203'/><link rel='alternate' type='text/html' href='http://hdegroot.blogspot.com/2006/09/images-in-vfp-grid-class.html' title='Images in a VFP grid class'/><author><name>Hans de Groot</name><uri>http://www.blogger.com/profile/06951165924122411855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_hAxQHDMy4bQ/SlSxqsliXkI/AAAAAAAAABI/78WZXTCCkpA/S220/hans100x127.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-30880849.post-115424074710322194</id><published>2006-07-30T08:16:00.000+02:00</published><updated>2006-07-30T11:34:09.240+02:00</updated><title type='text'>Listgrid - update 2</title><content type='html'>When using the vertical scroll bar to move through the grid, there where problems with the screen painting. Screen painting issues are also mentioned in VFP's help about the Scrolled event. However, it's now solved by changing some code in the Scrolled event of the grid.&lt;br /&gt;&lt;br /&gt;I also found two new issues to think about:&lt;br /&gt;1) You can select/deselect the current record with Ctrl+mouse click. However, when you move away from the this record by using the down or up arrow keys, the previous or next record is selected, but keeps the selected/deselected state of the previous record.&lt;br /&gt;2) When there are multiple records selected and you move to the right most column in the grid, there is allways some space at the right. You can see there that the inverted color of the current record continues in this 'empty column', but the other selected records don't.&lt;br /&gt;&lt;br /&gt;An updated download is available &lt;a href="http://www.datastudio.nl/download/foxproexamples/listgrid.zip"&gt;&lt;span style="FONT-WEIGHT: bold"&gt;here&lt;/span&gt;&lt;/a&gt; (ZIP compressed file, 44 kb).&lt;br /&gt;&lt;br /&gt;For more info about the Listgrid control, see the original post of July 16.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30880849-115424074710322194?l=hdegroot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hdegroot.blogspot.com/feeds/115424074710322194/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=30880849&amp;postID=115424074710322194' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/30880849/posts/default/115424074710322194'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/30880849/posts/default/115424074710322194'/><link rel='alternate' type='text/html' href='http://hdegroot.blogspot.com/2006/07/listgrid-update-2.html' title='Listgrid - update 2'/><author><name>Hans de Groot</name><uri>http://www.blogger.com/profile/06951165924122411855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_hAxQHDMy4bQ/SlSxqsliXkI/AAAAAAAAABI/78WZXTCCkpA/S220/hans100x127.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-30880849.post-115311638306830362</id><published>2006-07-17T08:02:00.000+02:00</published><updated>2006-07-21T16:50:34.343+02:00</updated><title type='text'>Listgrid - update</title><content type='html'>The listgrid control stopped responding, when you kept the Shift+Dn or Shift+Up keys pressed for a little while (in order to select multiple records). A 'thisform.draw' in the keypress event of the grid seems the solution to that problem.&lt;br /&gt;An updated download is available &lt;a href="http://www.datastudio.nl/download/foxproexamples/listgrid.zip"&gt;&lt;span style="FONT-WEIGHT: bold"&gt;here&lt;/span&gt;&lt;/a&gt; (ZIP compressed file, 44 kb).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30880849-115311638306830362?l=hdegroot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hdegroot.blogspot.com/feeds/115311638306830362/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=30880849&amp;postID=115311638306830362' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/30880849/posts/default/115311638306830362'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/30880849/posts/default/115311638306830362'/><link rel='alternate' type='text/html' href='http://hdegroot.blogspot.com/2006/07/listgrid-update.html' title='Listgrid - update'/><author><name>Hans de Groot</name><uri>http://www.blogger.com/profile/06951165924122411855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_hAxQHDMy4bQ/SlSxqsliXkI/AAAAAAAAABI/78WZXTCCkpA/S220/hans100x127.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-30880849.post-115304682764430253</id><published>2006-07-16T12:20:00.000+02:00</published><updated>2006-07-30T11:35:36.320+02:00</updated><title type='text'>Listgrid - a grid acting like a listview</title><content type='html'>A few month back, I decided to follow up on some ideas to make the VFP grid control act like a multi-select listview. In my applications I often use the MS listview control for this, but since MS stopped development on their core OCX controls, the listview control is beginning to show it's age with Windows 2000 style column headers in a XP world. The objective is to copy as much of the functionality of the MS listview. I just want to try how far this goes. If it doesn't work out, I'll switch to another third party OCX control. Here it is as it looks now:&lt;br /&gt;&lt;br /&gt;&lt;img src="http://photos1.blogger.com/blogger/7361/3319/320/listgrid.0.jpg" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-WEIGHT: bold"&gt;Features&lt;br /&gt;&lt;/span&gt;The class has the following features:&lt;span style="FONT-WEIGHT: bold"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold"&gt;&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold"&gt;&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold"&gt;&lt;/span&gt;&lt;ol&gt;&lt;li&gt;Multiselect option (set multiselect to .T.), using standard Windows keys (Shift, Ctrl combinations).&lt;/li&gt;&lt;li&gt;Sorting columns.&lt;/li&gt;&lt;li&gt;Have Pictures in columns.&lt;/li&gt;&lt;li&gt;Save and restore reordered columns, column widths and the column which was last sorted.&lt;/li&gt;&lt;li&gt;Export to Excel.&lt;/li&gt;&lt;/ol&gt;&lt;span style="FONT-WEIGHT: bold"&gt;Quick start&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Drop the class on a form.&lt;/li&gt;&lt;li&gt;Resize the container of the class to the desired size. The grid inside it will automatically size accordingly. &lt;/li&gt;&lt;li&gt;Set the recordsource property to the desired table/view/cursor.&lt;/li&gt;&lt;li&gt;Put code like this in the init method of the form:&lt;br /&gt;&lt;span style="COLOR: rgb(0,0,153);font-family:courier new;font-size:85%;"  &gt;IF !USED("CUSTOMER")&lt;br /&gt;USE CUSTOMER IN 0&lt;br /&gt;SELECT CUSTOMER&lt;br /&gt;ENDIF&lt;br /&gt;This.lGrid1.Multiselect = .T. &lt;span style="font-size:78%;"&gt;&amp;&amp;amp; multiselect if desired&lt;/span&gt;&lt;br /&gt;This.lGrid1.RecordSource = ALIAS()&lt;br /&gt;This.lGrid1.initialise()&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Run the form.&lt;/li&gt;&lt;/ol&gt;&lt;span style="FONT-WEIGHT: bold"&gt;Listgrid table&lt;/span&gt;&lt;br /&gt;There is a table called Listgrid, which contains column information for every recordsource used in the Listgrid class.&lt;br /&gt;The table is created if it does not allready exists and updated automatically with default column&lt;br /&gt;information for each recordsource opened by the class.&lt;br /&gt;In the supplied Listgrid table, there is allready information about the example Customer table.&lt;br /&gt;You can alter the data in the table, so you can have calculated fields and pictures in the grid.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;span style="COLOR: rgb(153,0,0);font-size:85%;" &gt;Table:&lt;/span&gt;&lt;span style="font-size:85%;"&gt; contains the same name for all records belonging to a certain recordsource&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="COLOR: rgb(153,0,0);font-size:85%;" &gt;Controlsrc:&lt;/span&gt;&lt;span style="font-size:85%;"&gt; you can see there are options to create a controlsource expression for every column&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="COLOR: rgb(153,0,0);font-size:85%;" &gt;Fieldtype:&lt;/span&gt;&lt;span style="font-size:85%;"&gt; data type of the column. You can use a 'P' for pictures&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="COLOR: rgb(153,0,0);font-size:85%;" &gt;Fieldwidth:&lt;/span&gt;&lt;span style="font-size:85%;"&gt; width of the field, not used by the listgrid class itself&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="COLOR: rgb(153,0,0);font-size:85%;" &gt;Decimals:&lt;/span&gt;&lt;span style="font-size:85%;"&gt; decimals of the field, not used by the listgrid class itself&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="COLOR: rgb(153,0,0);font-size:85%;" &gt;Descript:&lt;/span&gt;&lt;span style="font-size:85%;"&gt; shows up in the column header&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="COLOR: rgb(153,0,0);font-size:85%;" &gt;Alignment:&lt;/span&gt;&lt;span style="font-size:85%;"&gt; alignment of the header. 0 = left, 1 = right&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="COLOR: rgb(153,0,0);font-size:85%;" &gt;Disporder:&lt;/span&gt;&lt;span style="font-size:85%;"&gt; set the order in which the columns are shown&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="COLOR: rgb(153,0,0);font-size:85%;" &gt;Visible:&lt;/span&gt;&lt;span style="font-size:85%;"&gt; .False. for columns that must not show up&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="COLOR: rgb(153,0,0);font-size:85%;" &gt;Colwidth:&lt;/span&gt;&lt;span style="font-size:85%;"&gt; column width in pixels&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="COLOR: rgb(153,0,0);font-size:85%;" &gt;DispinXLS:&lt;/span&gt;&lt;span style="font-size:85%;"&gt; the column shows up in the Export2Excel option of the class&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="COLOR: rgb(153,0,0);font-size:85%;" &gt;Images:&lt;/span&gt;&lt;span style="font-size:85%;"&gt; list of images used for FieldType = "P"&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;span style="FONT-WEIGHT: bold"&gt;Pictures&lt;br /&gt;&lt;/span&gt;You can do the following to create a column with pictures in it:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;In the field images in the listgrid table, create a comma separated list of the images to use in the column. Just the filename is enough, as long as the images themselves are along the VFP path.&lt;/li&gt;&lt;li&gt;In the field Controlsrc create an expression which returns a text 'Image1', 'Image2' , 'Image3' , etc. for the image you want to show up. For example:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="COLOR: rgb(0,0,153)"&gt;IIF(MyField = "Man", "Image1", IIF(MyField = "Woman", "Image2", "Image3"))&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;Whenever the text in the field is "Man", the first image in the list shows up, for "Woman" the second, otherwise the third image.&lt;/li&gt;&lt;/ol&gt;&lt;span style="FONT-WEIGHT: bold"&gt;Export to excel&lt;/span&gt;&lt;br /&gt;To demonstrate the multiselect feature, there is a ExportToExcel method in the class to show the data of selected records in an Excel sheet. In the Example form, only the selected records show up in Excel with the optional where clause parameter.&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-WEIGHT: bold"&gt;Save/restore column widths&lt;/span&gt;&lt;br /&gt;The class has a Savesettings method to save information about reordered columns and changed column widths. See the Init and Destroy methods of the example form for a way to save and restore these settings.&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-WEIGHT: bold"&gt;Column sorting&lt;/span&gt;&lt;br /&gt;You can sort on a column by clicking it's header. This only works if it is possible to create an index. So in READ ONLY or EXCLUSIVE OFF situations, columns sorting does not work.&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-WEIGHT: bold"&gt;Issues&lt;br /&gt;&lt;/span&gt;This version of the class you can actually use. There are however still some issues.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Selecting records with Shift+Dn and Shift+Up eventually 'hangs' the grid control for a while, when you keep these keys pressed. I think there is something wrong with the DOSCROLL method. &lt;/li&gt;&lt;li&gt;Pressing Ctrl+A to select all records in the grid is handled through an ON KEY LABEL. This is, because the Ctrl+A key combination isn't handled by the Keypress event of the grid. The ON KEY LABEL is activated/deactivated in the WHEN and VALID events of the grid. However, when you click on de form itself and than return to the grid, the WHEN event is not triggeredand Ctrl+A isn't (re-)activated.&lt;/li&gt;&lt;li&gt;The dotted outline of the selected row is a VFP shape that does not look like 'the real thing', which has smaller dots. Maybe there is another solution with the use of GDI...&lt;/li&gt;&lt;li&gt;Scrolling records with the vertical scroll bar messes up the screen painting in the grid control.&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="FONT-WEIGHT: bold"&gt;Visual Foxpro version&lt;/span&gt;&lt;br /&gt;The Listgrid class makes use of the AllowSelection property which is introduced in VFP8, so VFP8 or higher is needed.&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-WEIGHT: bold"&gt;Download&lt;/span&gt;&lt;br /&gt;You can use this class every way you like, but for your own responsibility.&lt;br /&gt;Any positive comments and ideas are welcome at http://hdegroot.blogspot.com/&lt;br /&gt;&lt;br /&gt;A download as a ZIP compressed file (44 kb.) is available &lt;a href="http://www.datastudio.nl/download/foxproexamples/listgrid.zip"&gt;&lt;span style="FONT-WEIGHT: bold"&gt;here&lt;/span&gt;&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30880849-115304682764430253?l=hdegroot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hdegroot.blogspot.com/feeds/115304682764430253/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=30880849&amp;postID=115304682764430253' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/30880849/posts/default/115304682764430253'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/30880849/posts/default/115304682764430253'/><link rel='alternate' type='text/html' href='http://hdegroot.blogspot.com/2006/07/listgrid-grid-acting-like-listview.html' title='Listgrid - a grid acting like a listview'/><author><name>Hans de Groot</name><uri>http://www.blogger.com/profile/06951165924122411855</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_hAxQHDMy4bQ/SlSxqsliXkI/AAAAAAAAABI/78WZXTCCkpA/S220/hans100x127.jpg'/></author><thr:total>3</thr:total></entry></feed>
