Faceți căutări pe acest blog

marți, 24 martie 2026

The built-in monitor is black on my laptop, only external monitor seems to work

I have a laptop (Lenovo) with an external monitor connected through HDMI.

It has Windows 11 24H2 and all worked fine. After an update, suddenly, the laptop's built-in monitor turn to black and nothing is displayed, but the external monitor is fine.

I noticed that when the laptop starts, the Lenovo logo is displayed, so I guessed that nothing is wrong with the hardware, so I looked for Windows settings.

I tried all kind of settings, searched through WEB, but nothing helped me.

By chance, I noticed that the brightness slider what dragged to 0. I drag the slider to 100, and, voila, the laptop's screen is back.

After that, further search including the keyword "brightness", revealed a related post from 2022 including another Lenovo laptop with a similar issue.

marți, 20 mai 2025

Export to xlsx (class) 6.0 - support for inline strings

A new property was added, linline (boolean) and a new method, copytoinline.

By default linline = .F.

When linline = .T., instead of copytoxlsx, the new method, copytoinline is called. This way strings are generated as inline strings, not as a separate xml table.

A few errors were corrected to the old method, copytoxlsx, caused by memo fields with some special html characters (like ampersand or apostrophe).

I've found the inline strings useful when a table has dozens of type character fields.

This new version can be downloaded from here 

luni, 6 martie 2023

Internet Explorer and Windows 10

 Recently Internet Explorer was "replaced" by Edge in some versions of Windows 10.

"Where is my beloved Internet Explorer? Internet Explorer is Gone! Oh, No!"

I noticed that the solution used by Microsoft was to to add an add-on in Internet Explorer.

So I ran IExplorer "InPrivate" (right click on the IExplorer shortcut and choose InPrivate Browsing), then I clicked Manage add-ons (via Internet Options-> Programs)

There I saw an add-on called IeToEdge. This way I saw its name and where is stored

I propose two workarounds, both of them verified:

1) First I renamed the Exe file

To do that, I went to the folder pointed (in my case was C:\Program Files (x86)\Microsoft\Edge\Application\110.0.1587.63\BHO - but the version number could be different on other machines, and I've even found more than a single such folder, depending on how many updates the machine has), and renamed ie_to_edge_stub.exe into something else (like ie_to_edge_stub.exe.old)

2) Another approach was to leave the EXE file untouched, and delete the key from registry.

The appropriate key is located here: HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects, where I searched for a key that contains IeToEdge.

joi, 12 mai 2022

Combine icons/static cursors into one animated cursor

Like icons or static cursors, animated cursors are containers.

The structure is relatively simple. Besides the contained icons, you must provide the default speed of animation, the order in which frames are displayed (first frame is frame number 0) and the time in 1/60 sec for each step to be displayed (speed of animation)

Just look at the next code.

FUNCTION ico2ani

*****************************************************************
* Convert Icons (ICO) and cursor (CUR) to animated cursor (ANI) *
*****************************************************************
* Version 2.0
*****************************************************************
* Parameters
* - lcAni String Name of the resulted file
* - laIcons array (referrence) array containing fully qualified source files (icons or cursors)
* - lnDelay integer the time in 1/60 sec each image is displayed (default speed of animation)
* - laSeq array (refference) 2 dimensional array of integers containing :
* - column 1: the order in which frames are displayed (first frame is frame number 0)
* - column 2: time in 1/60 sec each step is displayed (speed of animation)
******************************************************************

LPARAMETERS lcAni,laIcons,lnDelay,laSeq
LOCAL lcIco[ALEN(m.laIcons)], lnLen[ALEN(m.laIcons)], lnLenIco, lnSteps, lcSeq, lcRate, lnLenSeq, lnLenRate, lnbfAttr
IF PCOUNT() < 2
RETURN
ENDIF
IF PCOUNT() = 2
lnDelay = 10
ENDIF
STORE 0 TO lnLenSeq, lnLenRate
STORE '' TO lcRate, lcSeq
lnbfAttr = 1
IF PCOUNT() < 4
lnSteps = ALEN(laIcons,1)
ELSE
lnSteps = ALEN(laSeq,1)
lnbfAttr = 3
FOR lni = 1 TO ALEN(laSeq,1)
IF TYPE("m.laSeq[1,1]") = "N"
lcSeq = m.lcSeq + BINTOC(m.laSeq[m.lni,1], "4RS")
ENDIF
IF TYPE("m.laSeq[1,2]") = "N"
lcRate = m.lcRate + BINTOC(m.laSeq[m.lni,2], "4RS")
ENDIF
NEXT
IF !EMPTY(m.lcRate)
lcRate = "rate" + BINTOC(LEN(m.lcRate), "4RS") + m.lcRate
ENDIF
IF !EMPTY(m.lcSeq)
lcSeq = "seq " + BINTOC(LEN(m.lcSeq), "4RS") + m.lcSeq
ENDIF
lnLenSeq = LEN(m.lcSeq)
lnLenRate = LEN(m.lcRate)
ENDIF

lnLenIco = 0
FOR lni = 1 TO ALEN(m.laIcons)
lcIco[m.lni] = FILETOSTR(m.laIcons[m.lni])
lnLen[m.lni] = LEN(m.lcIco[m.lni])
lnLenIco = m.lnLenIco + 8 + lnLen[m.lni]
NEXT

lcResult = "RIFF" + BINTOC(12 + 36 + 8 + 4 + m.lnLenIco + m.lnLenSeq + m.lnLenRate, "4RS")

lcResult = m.lcResult + "ACONanih" + BINTOC(36, "4RS") + BINTOC(36, "4RS") + BINTOC(ALEN(m.laIcons,1), "4RS") + BINTOC(m.lnSteps, "4RS") + ;
REPLICATE(CHR(0),16) + BINTOC(m.lnDelay, "4RS") + BINTOC(m.lnbfAttr, "4RS") + m.lcSeq + m.lcRate
lcResult = m.lcResult + "LIST" + BINTOC(4 + m.lnLenIco, "4RS")
lcResult = m.lcResult + "fram"
FOR lni = 1 TO ALEN(m.laIcons)
lcResult = m.lcResult + "icon" + BINTOC(m.lnLen[m.lni], "4RS") + m.lcIco[m.lni]
NEXT

STRTOFILE(m.lcResult, FORCEEXT(m.lcAni,"ani"))
RETURN FORCEEXT(m.lcAni,"ani")

Two demos:

1) Using faces:

CLEAR RESOURCES
CLEAR ALL
LOCAL laIcons[5], laSeq[8,2]
SET SAFETY OFF

* List of images
laIcons[1] = HOME(4)+"Icons\Misc\FACE01.ICO"
laIcons[2] = HOME(4)+"Icons\Misc\FACE02.ICO"
laIcons[3] = HOME(4)+"Icons\Misc\FACE03.ICO"
laIcons[4] = HOME(4)+"Icons\Misc\FACE04.ICO"
laIcons[5] = HOME(4)+"Icons\Misc\FACE05.ICO"

* order of frames
laSeq[1,1] = 0
laSeq[2,1] = 1
laSeq[3,1] = 2
laSeq[4,1] = 4
laSeq[5,1] = 2
laSeq[6,1] = 1
laSeq[7,1] = 0
laSeq[8,1] = 3

* time (speed) of each frame
laSeq[1,2] = 10
laSeq[2,2] = 10
laSeq[3,2] = 10
laSeq[4,2] = 10
laSeq[5,2] = 10
laSeq[6,2] = 10
laSeq[7,2] = 10
laSeq[8,2] = 60

lcAni = ico2ani("ff.ani",@laIcons,15,@laSeq)

PUBLIC ofrm
ofrm = CREATEOBJECT("form")
ofrm.MousePointer = 99
ofrm.MouseIcon = m.lcAni

ofrm.show()


2. Two animated cursor in the same demo:
* Code for testing purpose
CLEAR RESOURCES
CLEAR ALL
LOCAL laIcons[8],laIcons2[4]
SET SAFETY OFF

* create an animated cursor from 8 ICONS and set this to the form
laIcons[1] = HOME(4)+"Icons\Elements\MOON01.ICO"
laIcons[2] = HOME(4)+"Icons\Elements\MOON02.ICO"
laIcons[3] = HOME(4)+"Icons\Elements\MOON03.ICO"
laIcons[4] = HOME(4)+"Icons\Elements\MOON04.ICO"
laIcons[5] = HOME(4)+"Icons\Elements\MOON05.ICO"
laIcons[6] = HOME(4)+"Icons\Elements\MOON06.ICO"
laIcons[7] = HOME(4)+"Icons\Elements\MOON07.ICO"
laIcons[8] = HOME(4)+"Icons\Elements\MOON08.ICO"

lcAni = ico2ani("mm.ani",@laIcons,15)

* Create another animated cursor from 4 static CURSORS and set this to the optiongroup
laIcons2[1] = HOME(4)+"Cursors\H_WE.CUR"
laIcons2[2] = HOME(4)+"Cursors\H_NW.CUR"
laIcons2[3] = HOME(4)+"Cursors\H_NS.CUR"
laIcons2[4] = HOME(4)+"Cursors\H_NW.CUR"

lcAni = ico2ani("hh.ani",@laIcons2,15)

* Create the demo form with a optiongroup
PUBLIC ofrm
ofrm = CREATEOBJECT("form")

ofrm.MousePointer = 99
ofrm.MouseIcon = "mm.ani"

ofrm.addobject("optiongroup1","optiongroup")
ofrm.optiongroup1.buttoncount = 3
ofrm.optiongroup1.autosize = .t.
ofrm.optiongroup1.visible = .T.
ofrm.optiongroup1.MousePointer = 99
ofrm.optiongroup1.MouseIcon = "hh.ani"
ofrm.optiongroup1.setall("MousePointer", 99)
ofrm.optiongroup1.setall("MouseIcon", "hh.ani")

ofrm.show()

Related links

miercuri, 11 mai 2022

Generate icons from PNG pictures

 An icon (file with the "ico" extension( is a container, so it contains one or more pictures. To manage these pictures, the ico file has a simple header.

As you can see below, the same code can be used to generate a static cursor (a file with the "cur" extension), because there are only a few differences between icons and cursors.

The images must be no bigger than 256x256 pixels.
The images used can be bitmap (BMP) files or Portable Network Graphic (PNG) files, but the following code can be used only for PNG images.

Here is the code used by me:
FUNCTION genico
**********************************************
* Generates an ico file from one or more png *
**********************************************
* Parameters
* - array with the name (and path) of the png files (passed by reference)
* - name of the output file
* - llCur (optional) .F. (default) the result is icon /.T. the result is cursor
* - lnHotX (optional) the x coordinate for the hotspot (cursor only, where the mouse clicks) 
* - lnHotY (optional) the y coordinate for the hotspot (cursor only, where the mouse clicks)
**********************************************
LPARAMETERS laIcons,lcFileName,llCur,lnHotX,lnHotY
LOCAL lcResult,lcResult2,lnIcos,lni,lcImg,lnWidth,lnHeight,lnSize,lcS,llRes,lnOffset
IF PCOUNT() < 5 OR VARTYPE(m.lnHotY) <> "N"
lnHotY = 0
ENDIF
lnHotY = FLOOR(MIN(MAX(m.lnHotY,0),65535))
IF PCOUNT() < 4 OR VARTYPE(m.lnHotX) <> "N"
lnHotX = 0
ENDIF
lnHotX = FLOOR(MIN(MAX(m.lnHotX,0),65535))
IF PCOUNT() < 3 OR VARTYPE(m.llCur) <> "L"
llCur = .F.
ENDIF

llRes = .T.
lnIcos = ALEN(laIcons)
lcResult = CHR(0) + CHR(0) + CHR(IIF(m.llCur,2,1)) + CHR(0) + BINTOC(m.lnIcos, "2RS")
lcResult2 = ""
lnOffset = 6 + m.lnIcos * 16
FOR lni = 1 TO m.lnIcos
STORE 0 TO lnWidth,lnHeight,lnSize
lcS = ""
IF FILE(m.laIcons[m.lni])
IF is_png2(m.laIcons[m.lni],256,256,@lnWidth,@lnHeight,@lnSize,@lcS) = 0
IF !m.llCur
lcResult = m.lcResult + CHR(m.lnWidth) + CHR(m.lnHeight) + CHR(0) + CHR(0) + CHR(1) + CHR(0) + CHR(32) + CHR(0) + BINTOC(m.lnSize, "4RS") + BINTOC(m.lnOffset, "4RS")
ELSE
lcResult = m.lcResult + CHR(m.lnWidth) + CHR(m.lnHeight) + CHR(0)  + CHR(0) + BINTOC(MIN(m.lnHotX,m.lnWidth), "2RS") + BINTOC(MIN(m.lnHotY,m.lnHeight), "2RS") + BINTOC(m.lnSize, "4RS") + BINTOC(m.lnOffset, "4RS")
ENDIF
lcResult2 = m.lcResult2 + m.lcS
lnOffset = m.lnOffset + m.lnSize
ELSE
llRes = .F.
EXIT
ENDIF
ELSE
llRes = .F.
EXIT
ENDIF
NEXT
IF m.llRes 
STRTOFILE(m.lcResult + m.lcResult2,FORCEEXT(m.lcFileName,IIF(!m.llCur,"ico","cur")))
ENDIF
RETURN m.llRes

******************************************************************
*  Check if a file is png
* Compare width and height of the image is compared with maximum values
* Return the current width and height in pixels, the file size in bytes and the picture in the last parameters
******************************************************************
* Return value is
* 0 - success
* 1 - not a PNG
* 2 - too wide
* 4 - too high
* 8 - incorect number of parameters
******************************************************************
* is_png2 must be called with 7 parameters:
* - image file
* - maximum width
* - maximum height
* - (output) width in pixels
* - (output) height in pixels
* - (outut) size in bytes of the file
* - (output) the image file as a string
******************************************************************
FUNCTION is_png2
LPARAMETERS lcFil,lnWidthm,lnHeightm,lnWidth,lnHeight,lnSize,lcS
LOCAL llSgn,llIspng
llIspng=0
IF PCOUNT() < 6 OR VARTYPE(m.lnWidthm) <> "N" OR VARTYPE(m.lnHeightm) <> "N" OR VARTYPE(m.lcFil) <> "C" 
RETURN 8
ENDIF

lcs = FILETOSTR(FULLPATH(m.lcfil))
lnSize = LEN(m.lcs)
llsgn = ASC(SUBSTR(m.lcs,1,1))=137 and ASC(SUBSTR(m.lcs,2,1))=80 and ASC(SUBSTR(m.lcs,3,1))=78 and ASC(SUBSTR(m.lcs,4,1))=71 and ASC(SUBSTR(m.lcs,5,1))=13 and ASC(SUBSTR(m.lcs,6,1))=10 and ASC(SUBSTR(m.lcs,7,1))=26 and ASC(SUBSTR(m.lcs,8,1))=10
IF m.llsgn
lnWidth = ASC(SUBSTR(m.lcs,17))*256*256*256+ASC(SUBSTR(m.lcs,18))*256*256+ASC(SUBSTR(m.lcs,19))*256+ASC(SUBSTR(m.lcs,20))
IF m.lnWidth > m.lnWidthm
llIspng = m.llIspng + 2
ENDIF
IF m.lnWidth = 256
lnWidth = 0
ENDIF
lnHeight = ASC(SUBSTR(m.lcs,21))*256*256*256+ASC(SUBSTR(m.lcs,22))*256*256+ASC(SUBSTR(m.lcs,23))*256+ASC(SUBSTR(m.lcs,24))
IF m.lnHeight > m.lnHeightm
llIspng = m.llIspng + 4
ENDIF
IF m.lnHeight = 256
lnHeight = 0
ENDIF
ELSE
llIspng = m.llIspng + 1
ENDIF
RETURN m.llIspng

The can function can be use like this:

DIMENSION laIcons[1]
* icon
laIcons[1] = "villi_16.png"
?genico(@laIcons,"villi")
* cursor
laIcons[1] = "villi_32.png"
?genico(@laIcons,"villi_cur",.T.)


Related links

Generate icons from BMP pictures

An icon (file with the "ico" extension( is a container, so it contains one or more pictures. To manage these pictures, the ico file has a simple header.
As you can see below, the same code can be used to generate a static cursor (a file with the "cur" extension), because there are only a few differences between icons and cursors.

The images must be no bigger than 256x256 pixels.
The images used can be bitmap (BMP) files or Portable Network Graphic (PNG) files, but the following code can be used only for BMP images.

Here is the code used by me:
FUNCTION genicob
****************************************************
* Generates an ico / cur file from one or more bmp *
****************************************************
* Parameters
* - laIcons     array with the name (and path) of the bmp files (passed by reference)
* - lcFileName    name of the output file
* - llCur      (optional) .F. (default) the result is icon /.T. the result is cursor
* - lnHotX      (optional) the x coordinate for the hotspot (cursor only, where the mouse clicks)
* - lnHotY      (optional) the y coordinate for the hotspot (cursor only, where the mouse clicks)
**********************************************

LPARAMETERS laIcons,lcFileName,llCur,lnHotX,lnHotY
LOCAL lcResult,lcResult2,lnIcos,lni,lcImg,lnWidth,lnHeight,lnSize,lcS,lnBPix,lnColors,llRes,lnOffset
IF PCOUNT() < 5 OR VARTYPE(m.lnHotY) <> "N"
  lnHotY = 0
ENDIF
lnHotY = FLOOR(MIN(MAX(m.lnHotY,0),65535))
IF PCOUNT() < 4 OR VARTYPE(m.lnHotX) <> "N"
  lnHotX = 0
ENDIF
lnHotX = FLOOR(MIN(MAX(m.lnHotX,0),65535))
IF PCOUNT() < 3 OR VARTYPE(m.llCur) <> "L"
  llCur = .F.
ENDIF

llRes = .T.
lnIcos = ALEN(laIcons)
lcResult = CHR(0) + CHR(0) + CHR(IIF(m.llCur,2,1)) + CHR(0) + BINTOC(m.lnIcos, "2RS")
lcResult2 = ""
lnOffset = 6 + m.lnIcos * 16
FOR lni = 1 TO m.lnIcos
  STORE 0 TO lnWidth,lnHeight,lnSize,lnBPix,lnColors
  lcS = ""
  IF FILE(m.laIcons[m.lni])
    IF is_bmp2(m.laIcons[m.lni],256,256,@lnWidth,@lnHeight,@lnSize,@lcS,@lnBPix,@lnColors) = 0
      IF !m.llCur
        lcResult = m.lcResult + CHR(m.lnWidth) + CHR(m.lnHeight) + CHR(m.lnColors) + CHR(0) + CHR(1) + CHR(0) + BINTOC(m.lnBPix, "2RS") + BINTOC(m.lnSize, "4RS") + BINTOC(m.lnOffset, "4RS")
      ELSE
        lcResult = m.lcResult + CHR(m.lnWidth) + CHR(m.lnHeight) + CHR(m.lnColors) + CHR(0) + BINTOC(MIN(m.lnHotX,m.lnWidth), "2RS") + BINTOC(MIN(m.lnHotY,m.lnHeight), "2RS") + BINTOC(m.lnSize, "4RS") + BINTOC(m.lnOffset, "4RS")
      ENDIF
      lcResult2 = m.lcResult2 + m.lcS
      lnOffset = m.lnOffset + m.lnSize
    ELSE
      llRes = .F.
      EXIT
    ENDIF
  ELSE
    llRes = .F.
    EXIT
  ENDIF
NEXT
IF m.llRes
  STRTOFILE(m.lcResult + m.lcResult2,FORCEEXT(m.lcFileName,IIF(!m.llCur,"ico","cur")))
ENDIF
RETURN m.llRes

******************************************************************
* Check if a file is a bmp
* Compare width and height of the image is compared with maximum values
* Return the current width and height in pixels, the file size in bytes and the picture in the last parameters
******************************************************************
* Return value is
* 0 - success
* 1 - not a BMP
* 2 - too wide
* 4 - too high
* 8 - incorect number of parameters
******************************************************************
* is_bmp2 must be called with 9 parameters:
* - image file
* - maximum width
* - maximum height
* - (output) width in pixels
* - (output) height in pixels
* - (outut) size in bytes of the file
* - (output) the image file as a string
* - (output) the number bites per pixel
* - (output) the number of colors

******************************************************************
FUNCTION is_bmp2
LPARAMETERS lcFil,lnWidthm,lnHeightm,lnWidthR,lnHeightR,lnSize,lcS,lnBPix,lnColors
LOCAL llSgn,llIsbmp,lcS2,lcSourceRow,lnSourceRow,lnSourceRowLen,lnPixel,lcPixel,lcDestRow,lnSourceOff,lnSourcePixel,lnBytes,lnColorPixel,lnDestChar,lnDestPosPixel,lc2Pixels,lnWidth,lnHeight
llIsbmp=0
IF PCOUNT() < 6 OR VARTYPE(m.lnWidthm) <> "N" OR VARTYPE(m.lnHeightm) <> "N" OR VARTYPE(m.lcFil) <> "C"
  RETURN 8
ENDIF

lcs = FILETOSTR(FULLPATH(m.lcfil))
llsgn=ASC(SUBSTR(m.lcs,1,1))=66 and ASC(SUBSTR(m.lcs,2,1))=77
IF m.llsgn
  STORE CTOBIN(SUBSTR(m.lcs,19,4),"4RS") TO lnWidth,lnWidthR
  IF m.lnWidth > m.lnWidthm
    llIsbmp = m.llIsbmp + 2
  ENDIF
  IF m.lnWidth = 256
    lnWidthR = 0
  ENDIF
  STORE CTOBIN(SUBSTR(m.lcs,23,4),"4RS") TO lnHeight,lnHeightR
  IF m.lnHeight > m.lnHeightm
    llIsbmp = m.llIsbmp + 4
  ENDIF
  IF m.lnHeight = 256
    lnHeightR = 0
  ENDIF
  lnBPix = CTOBIN(SUBSTR(m.lcs,29,2),"2RS")
  lnColors = CTOBIN(SUBSTR(m.lcs,47,4),"4RS")
  * Prepare the mask
  lcS2 = ''
  lnSourceOff = 1 + CTOBIN(SUBSTR(m.lcs,11,4),"4RS") && bitmap offset
  DO CASE
  CASE MOD(m.lnBPix,8) = 0 && color depth = 8,16,24 or 32
    lnBytes = CEILING(m.lnBPix / 8)
    lnSourceRowLen = m.lnWidth * m.lnBytes && number of chars for a line of pixels
    IF MOD(m.lnSourceRowLen,4) <> 0 && is always rounded to 4 bytes (4 chars)
      lnSourceRowLen = m.lnSourceRowLen + 4 - MOD(m.lnSourceRowLen,4)
    ENDIF
    FOR lnSourceRow = 1 TO m.lnHeight
      lcSourceRow = SUBSTR(m.lcS, m.lnSourceOff + (m.lnSourceRow - 1) * m.lnSourceRowLen, m.lnSourceRowLen)
      lcDestRow = ''
      lnDestChar = 0
      lnDestPosPixel = 0
      FOR lnPixel = 1 TO m.lnWidth
        IF m.lnDestPosPixel = 8
          lcDestRow = m.lcDestRow + CHR(m.lnDestChar)
          m.lnDestPosPixel = 0
          lnDestChar = 0
        ENDIF
        lcPixel = SUBSTR(m.lcSourceRow,1 + (m.lnPixel - 1) * m.lnBytes, m.lnBytes)
        
        IF m.lnBytes = 3
          lnColorPixel = CTOBIN(m.lcPixel + CHR(0) , '4RS')
        ELSE
          lnColorPixel = CTOBIN(m.lcPixel , LTRIM(STR(m.lnBytes)) + 'RS')
        ENDIF
        IF BITXOR(m.lnColorPixel , CEILING(2 ^ m.lnBPix -1) ) = 0 &&AND m.lnColorPixel <> RGB(255,255,255)
          lnDestChar = BITSET(m.lnDestChar , 7-m.lnDestPosPixel)
        ENDIF
        lnDestPosPixel = m.lnDestPosPixel + 1
      NEXT
      lcDestRow = m.lcDestRow + CHR(m.lnDestChar)
      IF MOD(LEN(m.lcDestRow),4) <> 0
        lcDestRow = m.lcDestRow + REPLICATE(CHR(0),4 - MOD(LEN(m.lcDestRow),4))
      ENDIF
      lcS2 = m.lcS2 + m.lcDestRow
    NEXT
  CASE m.lnBPix = 4 && color depth = 4 (16 colors)
    lnBytes = 0.5
    lnSourceRowLen = m.lnWidth * m.lnBytes && number of chars for a line of pixels
    IF MOD(m.lnSourceRowLen,4) <> 0 && is always rounded to 4 bytes (4 chars)
      lnSourceRowLen = CEILING(m.lnSourceRowLen + 4 - MOD(m.lnSourceRowLen,4))
    ENDIF
    FOR lnSourceRow = 1 TO m.lnHeight
      lcSourceRow = SUBSTR(m.lcS, m.lnSourceOff + (m.lnSourceRow - 1) * m.lnSourceRowLen, m.lnSourceRowLen)
      lcDestRow = ''
      lnDestChar = 0
      lnDestPosPixel = 0
      FOR lnPixel = 1 TO m.lnWidth
        IF m.lnDestPosPixel = 8
          lcDestRow = m.lcDestRow + CHR(m.lnDestChar)
          m.lnDestPosPixel = 0
          lnDestChar = 0
        ENDIF
        IF MOD(m.lnPixel,2) = 1
          lc2Pixels = SUBSTR(m.lcSourceRow,1 + FLOOR(m.lnPixel / 2) , 1)
          lcPixel = SUBSTR(TRANSFORM(ASC(m.lc2Pixels),"@O"),9,1)
        ELSE
          lcPixel = RIGHT(TRANSFORM(ASC(m.lc2Pixels),"@O"),1)
        ENDIF
        
        IF ISDIGIT(m.lcPixel)
          lnColorPixel = VAL(m.lcPixel)
        ELSE
          lnColorPixel = ASC(m.lcPixel) - 55
        ENDIF
        IF BITXOR(m.lnColorPixel , 15 ) = 0
          lnDestChar = BITSET(m.lnDestChar , 7-m.lnDestPosPixel)
        ENDIF
        lnDestPosPixel = m.lnDestPosPixel + 1
      NEXT
      lcDestRow = m.lcDestRow + CHR(m.lnDestChar)
      IF MOD(LEN(m.lcDestRow),4) <> 0
        lcDestRow = m.lcDestRow + REPLICATE(CHR(0),4 - MOD(LEN(m.lcDestRow),4))
      ENDIF
      lcS2 = m.lcS2 + m.lcDestRow
    NEXT
  CASE m.lnBPix = 1 && monchrome
    lcS2 = SUBSTR(m.lcS, m.lnSourceOff)
  OTHERWISE
    lcS2 = ""
  ENDCASE
  IF m.lnHeight = 0
    lcS = SUBSTR(STUFF(m.lcS , 23, 4, BINTOC( 512,"4RS")),15) + m.lcS2
  ELSE
    lcS = SUBSTR(STUFF(m.lcS , 23, 4, BINTOC(2 * m.lnHeight,"4RS")),15) + m.lcS2
  ENDIF
  lnSize = LEN(m.lcs)
ELSE
  llIsbmp = m.llIsbmp + 1
ENDIF
RETURN m.llIsbmp


The code can be used like this:
DIMENSION laIcons[1]
* icon
laIcons[1] = HOME(4) + "Bitmaps\Tlbr_w95\SAVE.BMP"
?genicob(@laIcons,"SAVE")
* cursor
laIcons[1] = HOME(4) + "Bitmaps\Tlbr_w95\SAVE.BMP"
?genicob(@laIcons,"SAVE",.T.)

PUBLIC ofrm
ofrm = CREATEOBJECT("myform")
ofrm.show()

DEFINE CLASS myform as Form
icon = "SAVE.ico"
mousepointer = 99
mouseicon = "SAVE.cur"
ENDDEFINE

Check the attached icon.
First I have created a 256x256 24-bit BMP picture, using Windows Paint.
This picture I resized it (and saved) into another 4 pictures: 128x128, 64x64, 48x48 and 32x32
When necessary I made some fine adjustments to the resized pictures
Finally I have used MS Paint to create the 16x16 picture.
The generated icons contains all these six pictures. 



Related links

marți, 28 ianuarie 2020

Appendfromxls 3.2

The following situation was corrected:
When the table  has a numeric columns, but the spreadsheet has values formatted as string.

Download from
AppendFromXlsx 3.2


marți, 16 aprilie 2019

Dbf2Xlsx6 4.2

Bug fixed in function for VFP6 (bug found for strings longer than 19 characters)

Download from
Dbf2Xlsx6 4.2

Related posts
http://praisachion.blogspot.com/2016/06/inspectpptx-10.html
http://praisachion.blogspot.com/2016/06/inspectdocx-10.html

MSOffice -> DBF
http://praisachion.blogspot.com/2018/03/appendfromxlsx-31.html
http://praisachion.blogspot.com/2017/08/importfromxlsx-40.html
http://praisachion.blogspot.com/2017/06/append-from-xlsx-30.html
http://praisachion.blogspot.com/2016/08/importfromxlsx-34.html
http://praisachion.blogspot.com/2016/08/importfromxlsx-33.html
http://praisachion.blogspot.com/2016/06/importfromxlsx-32-appendfromxlsx-21.html
http://praisachion.blogspot.com/2016/06/appendfrompptx-10.html
http://praisachion.blogspot.com/2016/06/appendfromdocx-21.html
http://praisachion.blogspot.com/2016/06/importfromdocx-31.html
http://praisachion.blogspot.com/2016/06/importfrompptx-11.html
http://praisachion.blogspot.com/2016/06/importfromxlsx-31.html
http://praisachion.blogspot.com/2016/06/importfrompptx-10.html
http://praisachion.blogspot.com/2016/06/importfromdocx-30.html
http://praisachion.blogspot.com/2016/05/importfromxlsx-22.html
http://praisachion.blogspot.com/2016/02/import-dbf-from-msoffice-2007-xlsx-docx.html
http://praisachion.blogspot.com/2016/01/importfromdocx-20.html
http://praisachion.blogspot.com/2016/01/appendfromdocx-20.html
http://praisachion.blogspot.com/2016/01/importfromxlsx-13.html
http://praisachion.blogspot.com/2016/01/appendfromxlsx-20.html
http://praisachion.blogspot.com/2015/12/appendfromxlsx-15.html
http://praisachion.blogspot.com/2015/11/importfromxlsx-13.html
http://praisachion.blogspot.com/2015/09/importfromxlsx-12.html
http://praisachion.blogspot.com/2015/09/appendfromxlsx-14.html
http://praisachion.blogspot.com/2015/09/appendfromnxlsx-13.html
http://praisachion.blogspot.com/2015/08/importfromxlsx-11.html
http://praisachion.blogspot.com/2015/07/import-from-xlsx.html
http://praisachion.blogspot.com/2015/07/insert-from-focx.html
http://praisachion.blogspot.com/2015/06/append-from-docx.html

DBF -> MSOffice
Dbf2Xlsx6 4.2 (VFP6) 
http://praisachion.blogspot.com/2017/04/export-dbf-to-excel-2007.html
http://praisachion.blogspot.com/2017/01/export-dbf-to-msexcel-xlsx.html
http://praisachion.blogspot.com/2017/01/export-dbf-to-mspowerpoin-pptx.html
http://praisachion.blogspot.com/2017/01/export-dbf-to-msword-docx.html
http://praisachion.blogspot.com/2016/11/export-to-xlsx.html
http://praisachion.blogspot.com/2016/11/export-to-pptx.html
http://praisachion.blogspot.com/2016/11/export-to-docx.html
http://praisachion.blogspot.com/2016/11/export-from-vfp6-to-msoffice-docx-pptx.html
http://praisachion.blogspot.com/2016/09/copytoxlsx6-10.html
http://praisachion.blogspot.com/2016/01/export-dbf-to-msoffice-2007-xlsx-docx_24.html
http://praisachion.blogspot.com/2016/01/export-dbf-to-msoffice-2007-xlsx-docx.html
http://praisachion.blogspot.com/2016/01/exporttopptx-20.html
http://praisachion.blogspot.com/2016/01/exporttodocx-20.html
http://praisachion.blogspot.com/2016/01/copytopptx-20.html
http://praisachion.blogspot.com/2016/01/exporttoxlsx-20.html
http://praisachion.blogspot.com/2016/01/copytoxlsx-30.html
http://praisachion.blogspot.com/2015/12/exporttoxlsx-19-class.html
http://praisachion.blogspot.com/2015/12/copytoxlsx-210-procedure.html
http://praisachion.blogspot.com/2015/12/exporttoxlsx-18-class.html
http://praisachion.blogspot.com/2015/12/copytoxlsx-29.html
http://praisachion.blogspot.com/2015/02/export-pptx-13.html
http://praisachion.blogspot.com/2015/01/copytodocx-12.html
http://praisachion.blogspot.com/2015/01/exportdocx-1.html

OOffice -> DBF
http://praisachion.blogspot.com/2016/11/import-from-openoffice-libreoffice-for.html
http://praisachion.blogspot.com/2016/09/importfromoowrtext-10.html
http://praisachion.blogspot.com/2016/09/importfromooffice-1o.html
http://praisachion.blogspot.com/2016/08/importfromoocalc.html

DBF -> OOffice
http://praisachion.blogspot.com/2016/09/export-dbf-to-openoffice-libreoffice_52.html
http://praisachion.blogspot.com/2016/09/export-dbf-to-openoffice-libreoffice_16.html
http://praisachion.blogspot.com/2016/09/copy-to-ods-10-openoffice-calc.html
http://praisachion.blogspot.com/2016/09/export-dbf-to-openoffice-libreoffice.html
http://praisachion.blogspot.com/2016/09/copy-to-odt-10.html

 

luni, 19 martie 2018

AppendFromXlsx 3.1

A minor change (moved a line of code three lines upward), but with major impact

Download from
AppendFromXlsx 3.1
or
AppendFromXlsx 3.1 (alternate link)


Related posts
http://praisachion.blogspot.com/2016/06/inspectpptx-10.html
http://praisachion.blogspot.com/2016/06/inspectdocx-10.html

MSOffice -> DBF
http://praisachion.blogspot.com/2018/03/appendfromxlsx-31.html
http://praisachion.blogspot.com/2017/08/importfromxlsx-40.html
http://praisachion.blogspot.com/2017/06/append-from-xlsx-30.html
http://praisachion.blogspot.com/2016/08/importfromxlsx-34.html
http://praisachion.blogspot.com/2016/08/importfromxlsx-33.html
http://praisachion.blogspot.com/2016/06/importfromxlsx-32-appendfromxlsx-21.html
http://praisachion.blogspot.com/2016/06/appendfrompptx-10.html
http://praisachion.blogspot.com/2016/06/appendfromdocx-21.html
http://praisachion.blogspot.com/2016/06/importfromdocx-31.html
http://praisachion.blogspot.com/2016/06/importfrompptx-11.html
http://praisachion.blogspot.com/2016/06/importfromxlsx-31.html
http://praisachion.blogspot.com/2016/06/importfrompptx-10.html
http://praisachion.blogspot.com/2016/06/importfromdocx-30.html
http://praisachion.blogspot.com/2016/05/importfromxlsx-22.html
http://praisachion.blogspot.com/2016/02/import-dbf-from-msoffice-2007-xlsx-docx.html
http://praisachion.blogspot.com/2016/01/importfromdocx-20.html
http://praisachion.blogspot.com/2016/01/appendfromdocx-20.html
http://praisachion.blogspot.com/2016/01/importfromxlsx-13.html
http://praisachion.blogspot.com/2016/01/appendfromxlsx-20.html
http://praisachion.blogspot.com/2015/12/appendfromxlsx-15.html
http://praisachion.blogspot.com/2015/11/importfromxlsx-13.html
http://praisachion.blogspot.com/2015/09/importfromxlsx-12.html
http://praisachion.blogspot.com/2015/09/appendfromxlsx-14.html
http://praisachion.blogspot.com/2015/09/appendfromnxlsx-13.html
http://praisachion.blogspot.com/2015/08/importfromxlsx-11.html
http://praisachion.blogspot.com/2015/07/import-from-xlsx.html
http://praisachion.blogspot.com/2015/07/insert-from-focx.html
http://praisachion.blogspot.com/2015/06/append-from-docx.html

DBF -> MSOffice
Dbf2Xlsx6 4.2 (VFP6) 
http://praisachion.blogspot.com/2017/04/export-dbf-to-excel-2007.html
http://praisachion.blogspot.com/2017/01/export-dbf-to-msexcel-xlsx.html
http://praisachion.blogspot.com/2017/01/export-dbf-to-mspowerpoin-pptx.html
http://praisachion.blogspot.com/2017/01/export-dbf-to-msword-docx.html
http://praisachion.blogspot.com/2016/11/export-to-xlsx.html
http://praisachion.blogspot.com/2016/11/export-to-pptx.html
http://praisachion.blogspot.com/2016/11/export-to-docx.html
http://praisachion.blogspot.com/2016/11/export-from-vfp6-to-msoffice-docx-pptx.html
http://praisachion.blogspot.com/2016/09/copytoxlsx6-10.html
http://praisachion.blogspot.com/2016/01/export-dbf-to-msoffice-2007-xlsx-docx_24.html
http://praisachion.blogspot.com/2016/01/export-dbf-to-msoffice-2007-xlsx-docx.html
http://praisachion.blogspot.com/2016/01/exporttopptx-20.html
http://praisachion.blogspot.com/2016/01/exporttodocx-20.html
http://praisachion.blogspot.com/2016/01/copytopptx-20.html
http://praisachion.blogspot.com/2016/01/exporttoxlsx-20.html
http://praisachion.blogspot.com/2016/01/copytoxlsx-30.html
http://praisachion.blogspot.com/2015/12/exporttoxlsx-19-class.html
http://praisachion.blogspot.com/2015/12/copytoxlsx-210-procedure.html
http://praisachion.blogspot.com/2015/12/exporttoxlsx-18-class.html
http://praisachion.blogspot.com/2015/12/copytoxlsx-29.html
http://praisachion.blogspot.com/2015/02/export-pptx-13.html
http://praisachion.blogspot.com/2015/01/copytodocx-12.html
http://praisachion.blogspot.com/2015/01/exportdocx-1.html

OOffice -> DBF
http://praisachion.blogspot.com/2016/11/import-from-openoffice-libreoffice-for.html
http://praisachion.blogspot.com/2016/09/importfromoowrtext-10.html
http://praisachion.blogspot.com/2016/09/importfromooffice-1o.html
http://praisachion.blogspot.com/2016/08/importfromoocalc.html

DBF -> OOffice
http://praisachion.blogspot.com/2016/09/export-dbf-to-openoffice-libreoffice_52.html
http://praisachion.blogspot.com/2016/09/export-dbf-to-openoffice-libreoffice_16.html
http://praisachion.blogspot.com/2016/09/copy-to-ods-10-openoffice-calc.html
http://praisachion.blogspot.com/2016/09/export-dbf-to-openoffice-libreoffice.html
http://praisachion.blogspot.com/2016/09/copy-to-odt-10.html

 

joi, 4 ianuarie 2018

Changing the hyperlink tooltip

Editboxes can allow following hyperlinks by setting EnableHyperlinks = .T.
In this case, any hyperlink is enhanced (the forecolor is blue and is underlined), and performing a CTRL+click, the default browser is launched.

If the form has Showtips = .T., then the tooltip "CTRL + click to follow the link" is showed each time you point to a hyperlink.

The application object _VFP, has a property named EditorOptions, which allow to switch between CTRL + click and Click to follow hyperlinks (among other things).
EditorOptions is a string, and contains by default "K", meaning CTRL +click for hyperlinks.
If you change "K" into "k", then only a mouse click is needed for the same action (without pressing CTRL).


PUBLIC ofrm
_vfp.EditorOptions = CHRTRAN(_vfp.EditorOptions, "K", "k") && Click instead of CTRL+Click
ofrm = CREATEOBJECT("MyForm")
ofrm.Show()

DEFINE CLASS MyForm as Form
      Showtips = .T.
      ADD OBJECT ed as Editbox WITH Value = "www.foxite.com" + CHR(13) + CHR(13) + "www.google.com",;
             EnableHyperlinks = .T.,;
             width = 300
ENDDEFINE


But the hyperlink tooltip remains unchanged, i.e. shows "CTRL + click to follow the link".

If you want to change this into "Click to follow the link", you have two options.
The easiest way is to disable the hyperlinks tooltip, and to add your own tooltip to editbox.

PUBLIC ofrm
_vfp.EditorOptions = CHRTRAN(_vfp.EditorOptions, "K", "k") && Click instead of CTRL+Click
sys(3008,0) && disable hyperlink tooltips
ofrm = CREATEOBJECT("MyForm")
ofrm.Show()

DEFINE CLASS MyForm as Form
      Showtips = .T.
      ADD OBJECT ed as Editbox WITH Value = "www.foxite.com" + CHR(13) + CHR(13) + "www.google.com",;
             EnableHyperlinks = .T.,;
             width = 300,;
             ToolTipText = "Click to follow link"
ENDDEFINE
 

But pointing hyperlinks, no tooltip is shown.

The second option is to edit (hack) the resource file. The file is stored in HOME(1), and depending on the language, this file is named VFP9ENU.DLL, VFP9KOR.DLL a.s.o

Because all you need is to change a string, you have to locate the position of the string, and to change it into another null-char ended string, with the same length.
Be aware that this is a potential dangerous action.
Make a copy of your DLL, before trying the next one (step one).


1) First made a safety copy of your DLL
2) move it from HOME(1) + VFP9ENU.DLL into a folder with enough rights (d:\teste in the next demo)
3) Run the next prg

ln = FOPEN("d:\teste\VFP9ENU.DLL",12)
?ln
?FSEEK(m.ln,0x5ef8) && 0x5ef8 is the offset of the "CTRL + click to follow link" message
lc = FGETS(m.ln,27) && 27 is the length of the "CTRL + click to follow link" message
lc = "Click to follow link" + REPLICATE(CHR(0),7) && the new message (7 is the number of deleted characters)
?FSEEK(m.ln,0x5ef8)
?FPUTS(m.ln,m.lc,27)
?FCLOSE(m.ln)

 4) copy the modified DLL back to HOME(1)

Similar steps can be made to the runtime DLL, stored in C:\Program Files\Common Files\microsoft shared\VFP and named VFP9RENU.DLL

The prg is a little different, because the string starts from another  byte

ln = FOPEN("d:\teste\VFP9RENU.DLL",12)
?ln
?FSEEK(m.ln,0x5e30) && 0x5e30 is the offset of the "CTRL + click to follow link" message
lc = FGETS(m.ln,27) && 27 is the length of the "CTRL + click to follow link" message
lc = "Click to follow link" + REPLICATE(CHR(0),7) && the new message (7 is the number of deleted characters)
?FSEEK(m.ln,0x5e30)
?FPUTS(m.ln,m.lc,27)
?FCLOSE(m.ln)
RETURN

duminică, 26 noiembrie 2017

"Typing" characters programatically (4)

As a practical application, here is a simple way to extract the content of an editbox, row by row

In the next demo, type whatever you want in the edit box, and click the form to see the "extraction" process

PUBLIC ofrm
ofrm = CREATEOBJECT("myform")
ofrm.show()

DEFINE CLASS myform as Form
 autocenter = .T.
 ADD OBJECT edt as myeditbox && addlinefeeds = .F. && successfully tested
 PROCEDURE click
  LOCAL lnStart,lnLen
  * keep the potential selection 
  lnStart = This.edt.SelStart
  lnSen = This.edt.SelLength
  * Jump to the beginning of editbox
  This.edt.keypress(1,2,.T.) &&CTRL+HOME
  DO WHILE .T.
   * go to the beginning of the row
   This.edt.keypress(1,0,.T.) && HOME
   * select to the end of the row
   This.edt.keypress(49,1,.T.) &&SHIFT+END
   * type the row content
   ACTIVATE SCREEN 
   ?This.edt.seltext
   * test if the task was completed
   IF This.edt.Selstart + This.edt.Sellength = LEN(This.edt.value)
    EXIT
   ENDIF
   *adwance to the next row
   This.edt.keypress(24,0,.T.) && DOWN ARROW
  ENDDO 
  * restore the selection
  This.edt.SelStart = m.lnStart 
  This.edt.SelLength = m.lnSen 
 ENDPROC
ENDDEFINE

DEFINE CLASS myeditbox as EditBox
 PROCEDURE keypress
  LPARAMETERS nkey,nshift,lraise
  IF m.lraise
   DODEFAULT(m.nkey,m.nshift)
   =This.Value
  ENDIF
 ENDPROC
ENDDEFINE 
 
Related links
[1] "Typing" characters programatically 
[2] "Typing" characters programatically (2) 
[3] "Typing" characters programatically (3) 

miercuri, 8 noiembrie 2017

"Typing" characters programmatically (3)

In my previous post [2] I show how to add characters in a textbox, without using the keyboard or using the KWYBOARD command, but altering the keyboard() event.
The major drawback of the solution, was that if the textbox has a controlsource, the variable from the controlsource isn't updated and the value property isn't preserved.
Also, the reason for that behavior is the switch of the order of the interactivechange(0 and keypress().

As a solution, I propose to simply update the controlsource in the interactivechange.
The next example shows this, having as controlsource a memory variable in txt2 and a cursor field in txt3. Next to this example follows several others, showing the same trick applied to editbox, combobox, grid, and with other data type, like number and date.


PUBLIC ofrm,lcVar
CLEAR
lcVar = ""
ofrm=CREATEOBJECT("MyForm")
ofrm.show()
DEFINE CLASS MyForm as Form
      autocenter = .T.
      ADD OBJECT txt2 as MyText2 WITH width = 225, ControlSource = "lcVar"
      ADD OBJECT txt3 as MyText2 WITH top=50, width = 225, ControlSource = "cCur.cVar"
      ADD OBJECT cmd as CommandButton WITH left=250,Caption='click',Autosize=.T.
      PROCEDURE load
            CREATE CURSOR cCur (cVar C(120))
            APPEND BLANK
      ENDPROC
      PROCEDURE cmd.click
            FOR lni = 97 TO 106
                  ThisForm.txt2.Keypress(m.lni,0,.T.) && A
            NEXT
            ThisForm.txt2.Keypress(13,0,.T.) && Enter
            FOR lni = 65 TO 86
                  ThisForm.txt3.Keypress(m.lni,0,.T.) && A
            NEXT
            ThisForm.txt3.Keypress(13,0,.T.) && Enter
      ENDPROC
      PROCEDURE click
            ACTIVATE SCREEN
            ?'lcVar = ['+m.lcVar+']','cCur=['+cCur.cVar+']'
ENDDEFINE
*********************
* Text box class 2
*********************
DEFINE CLASS MyText2 as TextBox
      PROCEDURE keypress
            LPARAMETERS nKey,nShift,lraised
            IF lraised
                  DODEFAULT(nKey,nShift)
                  =This.value
            ENDIF
      ENDPROC
      PROCEDURE interactivechange
            IF !EMPTY(This.ControlSource)
                  TRY
                        replace (This.ControlSource) WITH (This.Value)
                  CATCH
                        STORE (This.Value) TO (This.ControlSource)
                  ENDTRY
            ENDIF
      ENDPROC
ENDDEFINE

The next example illustrate the same approach applied to editboxes (I changed only the baseclass type)

PUBLIC ofrm,lcVar
CLEAR
lcVar = ""
ofrm=CREATEOBJECT("MyForm")
ofrm.show()
DEFINE CLASS MyForm as Form
      autocenter = .T.
      ADD OBJECT txt2 as MyText2 WITH width = 225, ControlSource = "lcVar"
      ADD OBJECT txt3 as MyText2 WITH top=100, width = 225, ControlSource = "cCur.cVar"
      ADD OBJECT cmd as CommandButton WITH left=250,Caption='click',Autosize=.T.
      PROCEDURE load
            CREATE CURSOR cCur (cVar C(120))
            APPEND BLANK
      ENDPROC
      PROCEDURE cmd.click
            FOR lni = 97 TO 105
                  ThisForm.txt2.Keypress(m.lni,0,.T.) && A
            NEXT
            ThisForm.txt2.Keypress(13,0,.T.) && Enter
            FOR lni = 66 TO 86
                  ThisForm.txt3.Keypress(m.lni,0,.T.) && A
            NEXT
            ThisForm.txt3.Keypress(13,0,.T.) && Enter
      ENDPROC
      PROCEDURE click
            ACTIVATE SCREEN
            ?'lcVar = ['+m.lcVar+']','cCur=['+cCur.cVar+']'
ENDDEFINE
*********************
* Text box class 2
*********************
DEFINE CLASS MyText2 as EditBox
      PROCEDURE keypress
            LPARAMETERS nKey,nShift,lraised
            IF lraised
                  DODEFAULT(nKey,nShift)
                  =This.value
            ENDIF
      ENDPROC
      PROCEDURE interactivechange
            IF !EMPTY(This.ControlSource)
                  TRY
                        replace (This.ControlSource) WITH (This.Value)
                  CATCH
                        STORE (This.Value) TO (This.ControlSource)
                  ENDTRY
            ENDIF
      ENDPROC
ENDDEFINE
  

And the same approach applied to comboboxes (I changed only the baseclass type)
PUBLIC ofrm,lcVar
CLEAR
lcVar = ""
ofrm=CREATEOBJECT("MyForm")
ofrm.show()
DEFINE CLASS MyForm as Form
      autocenter = .T.
      ADD OBJECT txt2 as MyText2 WITH width = 225, ControlSource = "lcVar"
      ADD OBJECT txt3 as MyText2 WITH top=50, width = 225, ControlSource = "cCur.cVar"
      ADD OBJECT cmd as CommandButton WITH left=250,Caption='click',Autosize=.T.
      PROCEDURE load
            CREATE CURSOR cCur (cVar C(120))
            APPEND BLANK
      ENDPROC
      PROCEDURE cmd.click
            FOR lni = 97 TO 105
                  ThisForm.txt2.Keypress(m.lni,0,.T.) && A
            NEXT
            ThisForm.txt2.Keypress(13,0,.T.) && Enter
            FOR lni = 66 TO 86
                  ThisForm.txt3.Keypress(m.lni,0,.T.) && A
            NEXT
            ThisForm.txt3.Keypress(13,0,.T.) && Enter
      ENDPROC
      PROCEDURE click
            ACTIVATE SCREEN
            ?'lcVar = ['+m.lcVar+']','cCur=['+cCur.cVar+']'
ENDDEFINE
*********************
* Text box class 2
*********************
DEFINE CLASS MyText2 as ComboBox
      PROCEDURE keypress
            LPARAMETERS nKey,nShift,lraised
            IF lraised
                  DODEFAULT(nKey,nShift)
                  =This.value
            ENDIF
      ENDPROC
      PROCEDURE interactivechange
            IF !EMPTY(This.ControlSource)
                  TRY
                        replace (This.ControlSource) WITH (This.Value)
                  CATCH
                        STORE (This.Value) TO (This.ControlSource)
                  ENDTRY
            ENDIF
      ENDPROC
ENDDEFINE

Now let's try with a grid

PUBLIC ofrm,lcVar
CLEAR
lcVar = ""
ofrm=CREATEOBJECT("MyForm")
ofrm.show()
DEFINE CLASS MyForm as Form
      autocenter = .T.
      ADD OBJECT grd as grid WITH Recordsource = "cCur",allowaddnew = .T.
      ADD OBJECT cmd as CommandButton WITH left=325,Caption='click',Autosize=.T.
      PROCEDURE load
            CREATE CURSOR cCur (cVar C(120))
            APPEND BLANK
            APPEND BLANK
            APPEND BLANK
            GO TOP
      ENDPROC
      PROCEDURE Init
            This.grd.Column1.RemoveObject("Text1")
            This.grd.Column1.AddObject("Text1","MyText2")
            This.grd.Column1.Text1.Visible = .T.
      PROCEDURE cmd.click
            FOR lni = 97 TO 105
                  ThisForm.grd.Column1.Text1.Keypress(m.lni,0,.T.) && A
            NEXT
            ThisForm.grd.Column1.Text1.Keypress(13,0,.T.) && Enter
      ENDPROC
      PROCEDURE click
            ACTIVATE SCREEN
            ?'lcVar = ['+m.lcVar+']','cCur=['+cCur.cVar+']'
ENDDEFINE
*********************
* Text box class 2
*********************
DEFINE CLASS MyText2 as TextBox
      margin = 0
      borderstyle = 0
      PROCEDURE keypress
            LPARAMETERS nKey,nShift,lraised
            IF lraised
                  DODEFAULT(nKey,nShift)
                  =This.value
            ENDIF
      ENDPROC
      PROCEDURE interactivechange
            IF !EMPTY(This.ControlSource)
                  TRY
                        replace (This.ControlSource) WITH (This.Value)
                  CATCH
                        STORE (This.Value) TO (This.ControlSource)
                  ENDTRY
            ENDIF
      ENDPROC
ENDDEFINE
 
Now having numeric variable and field
PUBLIC ofrm,lcVar
CLEAR
lcVar = 0
ofrm=CREATEOBJECT("MyForm")
ofrm.show()
DEFINE CLASS MyForm as Form
      autocenter = .T.
      ADD OBJECT txt2 as MyText2 WITH width = 225, ControlSource = "lcVar"
      ADD OBJECT txt3 as MyText2 WITH top=50, width = 225, ControlSource = "cCur.cVar"
      ADD OBJECT cmd as CommandButton WITH left=250,Caption='click',Autosize=.T.
      PROCEDURE load
            CREATE CURSOR cCur (cVar N(20))
            APPEND BLANK
      ENDPROC
      PROCEDURE cmd.click
            FOR lni = 53 TO 55
                  ThisForm.txt2.Keypress(m.lni,0,.T.) && A
            NEXT
            ThisForm.txt2.Keypress(13,0,.T.) && Enter
            FOR lni = 48 TO 52
                  ThisForm.txt3.Keypress(m.lni,0,.T.) && A
            NEXT
            ThisForm.txt3.Keypress(13,0,.T.) && Enter
      ENDPROC
      PROCEDURE click
            ACTIVATE SCREEN
            ?'lcVar = ',m.lcVar,'cCur=',cCur.cVar
ENDDEFINE
*********************
* Text box class 2
*********************
DEFINE CLASS MyText2 as TextBox
      PROCEDURE keypress
            LPARAMETERS nKey,nShift,lraised
            IF lraised
                  DODEFAULT(nKey,nShift)
                  =This.value
            ENDIF
      ENDPROC
      PROCEDURE interactivechange
            IF !EMPTY(This.ControlSource)
                  TRY
                        replace (This.ControlSource) WITH (This.Value)
                  CATCH
                        STORE (This.Value) TO (This.ControlSource)
                  ENDTRY
            ENDIF
      ENDPROC
ENDDEFINE

Finally, having date variable and field

PUBLIC ofrm,lcVar
CLEAR
lcVar = {}
ofrm=CREATEOBJECT("MyForm")
ofrm.show()
DEFINE CLASS MyForm as Form
      autocenter = .T.
      ADD OBJECT txt2 as MyText2 WITH width = 225, ControlSource = "lcVar"
      ADD OBJECT txt3 as MyText2 WITH top=50, width = 225, ControlSource = "cCur.cVar"
      ADD OBJECT cmd as CommandButton WITH left=250,Caption='click',Autosize=.T.
      PROCEDURE load
            CREATE CURSOR cCur (cVar D)
            APPEND BLANK
      ENDPROC
      PROCEDURE cmd.click
            FOR lni = 1 TO 6
                  ThisForm.txt2.Keypress(49,0,.T.) && A
            NEXT
            ThisForm.txt2.Keypress(13,0,.T.) && Enter
            FOR lni = 1 TO 6
                  ThisForm.txt3.Keypress(49,0,.T.) && A
            NEXT
            ThisForm.txt3.Keypress(13,0,.T.) && Enter
      ENDPROC
      PROCEDURE click
            ACTIVATE SCREEN
            ?'lcVar = ',m.lcVar,'cCur=',cCur.cVar
ENDDEFINE
*********************
* Text box class 2
*********************
DEFINE CLASS MyText2 as TextBox
      PROCEDURE keypress
            LPARAMETERS nKey,nShift,lraised
            IF lraised
                  DODEFAULT(nKey,nShift)
                  =This.value
            ENDIF
      ENDPROC
      PROCEDURE interactivechange
            IF !EMPTY(This.ControlSource)
                  TRY
                        replace (This.ControlSource) WITH (This.Value)
                  CATCH
                        STORE (This.Value) TO (This.ControlSource)
                  ENDTRY
            ENDIF
      ENDPROC
ENDDEFINE

 See also