We've seen many attempts to calculate cell coordinates in Basic+ - we've even done it a few times ourselves and it's quite a pain, having to take into account all the different styles of the edit table, the width of columns, which columns are hidden and so forth.
Well, there's a really easy way to do this, and that's by asking the EditTable itself what the coordinates are via the standard Windows API SendMessage function. We just need to know what message to send to the EditTable.
DTM_READCELLRECT
The message we need is called DTM_READCELLRECT, and it returns the coordinates of the cell identified via the ACCESSPOS property. All we need to do is pass it the address of a RECT structure to fill in, which we then translate into a dynamic array which we can use further.
Here's a simple function to demonstrate this:
0001 compile function edt_GetCellRect( edtID, colNo, rowNo )
0002 /*
0003 Author : Darth C, Sprezzatura Actual
0004 Date : Sep 09
0005 Purpose : Function to return edit table cell coordinates
0006
0007 Parameters
0008 ==========
0009
0010 edtID -> Fully qualified name of the edit table
0011
0012 colNo -> Column number of the target cell. Defaults
0013 to currentPos
0014
0015 rowNo -> Row number of the target cell. Defaults to
0016 currentPos
0017
0018 Returns
0019 =======
0020
0021 Returns the edit table cell coordinates as per the RECT
0022 structure layout, i.e.
0023
0024 <1> Left
0025 <2> Top
0026 <3> Right
0027 <4> Bottom
0028
0029 Note these coordinates are relative to the Edit Table
0030 CLIENT area, NOT the desktop/screen!
0031
0032 */
0033 declare function sendMessage, blank_Struct, struct_To_Var
0034 declare function get_Property
0035
0036 equ DTM_READCELLRECT$ to 1079 ; * // (WM_USER + 55)
0037 equ DTA_ACCESS$ to 0x0000
0038
0039 if assigned( edtID ) else edtID = ""
0040 if assigned( colNo ) else colNo = ""
0041 if assigned( rowNo ) else rowNo = ""
0042
0043 if len( edtID ) else
0044 return ""
0045 end
0046
0047 if len( colNo ) and len( rowNo ) then
0048 call set_Property( edtID, "ACCESSPOS", colNo : @fm : rowNo )
0049 end else
0050 * // Use the current "caret" position - ensure ACCESSPOS
0051 * // is sync'd with CARETPOS
0052 call set_Property( edtID, "ACCESSPOS", |
0053 get_Property( edtID, "CARETPOS" ) )
0054 end
0055
0056 * // Create a blank RECT structure for the edit table
0057 * // to fill for us and lock it
0058 rc = blank_Struct( "RECT" )
0059 lockVariable rc as BINARY
0060
0061 * // Send the DTM_READCELLRECT message.
0062 * //
0063 * // The third parameter (wParam) contains a value that
0064 * // tells the edittable which cell we want. DTA_ACCESS
0065 * // means "use the ACCESSPOS property".
0066 * //
0067 * // We send the address of the RECT structure to fill in
0068 * // as the last parameter (lParam).
0069 call sendMessage( get_Property( edtID, "HANDLE" ), |
0070 DTM_READCELLRECT$, |
0071 DTA_ACCESS$, |
0072 getPointer( rc ) )
0073
0074 * // Unlock and translate the structure to a
0075 * // dynamic array
0076 unlockVariable rc
0077 rc = struct_To_Var( rc, "RECT" )
0078
0079 return rc
0002 /*
0003 Author : Darth C, Sprezzatura Actual
0004 Date : Sep 09
0005 Purpose : Function to return edit table cell coordinates
0006
0007 Parameters
0008 ==========
0009
0010 edtID -> Fully qualified name of the edit table
0011
0012 colNo -> Column number of the target cell. Defaults
0013 to currentPos
0014
0015 rowNo -> Row number of the target cell. Defaults to
0016 currentPos
0017
0018 Returns
0019 =======
0020
0021 Returns the edit table cell coordinates as per the RECT
0022 structure layout, i.e.
0023
0024 <1> Left
0025 <2> Top
0026 <3> Right
0027 <4> Bottom
0028
0029 Note these coordinates are relative to the Edit Table
0030 CLIENT area, NOT the desktop/screen!
0031
0032 */
0033 declare function sendMessage, blank_Struct, struct_To_Var
0034 declare function get_Property
0035
0036 equ DTM_READCELLRECT$ to 1079 ; * // (WM_USER + 55)
0037 equ DTA_ACCESS$ to 0x0000
0038
0039 if assigned( edtID ) else edtID = ""
0040 if assigned( colNo ) else colNo = ""
0041 if assigned( rowNo ) else rowNo = ""
0042
0043 if len( edtID ) else
0044 return ""
0045 end
0046
0047 if len( colNo ) and len( rowNo ) then
0048 call set_Property( edtID, "ACCESSPOS", colNo : @fm : rowNo )
0049 end else
0050 * // Use the current "caret" position - ensure ACCESSPOS
0051 * // is sync'd with CARETPOS
0052 call set_Property( edtID, "ACCESSPOS", |
0053 get_Property( edtID, "CARETPOS" ) )
0054 end
0055
0056 * // Create a blank RECT structure for the edit table
0057 * // to fill for us and lock it
0058 rc = blank_Struct( "RECT" )
0059 lockVariable rc as BINARY
0060
0061 * // Send the DTM_READCELLRECT message.
0062 * //
0063 * // The third parameter (wParam) contains a value that
0064 * // tells the edittable which cell we want. DTA_ACCESS
0065 * // means "use the ACCESSPOS property".
0066 * //
0067 * // We send the address of the RECT structure to fill in
0068 * // as the last parameter (lParam).
0069 call sendMessage( get_Property( edtID, "HANDLE" ), |
0070 DTM_READCELLRECT$, |
0071 DTA_ACCESS$, |
0072 getPointer( rc ) )
0073
0074 * // Unlock and translate the structure to a
0075 * // dynamic array
0076 unlockVariable rc
0077 rc = struct_To_Var( rc, "RECT" )
0078
0079 return rc
(The more pedantic amongst you may notice that we didn't reset ACCESSPOS after we updated it. The reason for this is simple - every low-level function in the EditTable updates ACCESSPOS to the required coordinates before executing, and you should never assume ACCESSPOS is at the correct coordinates - always set it yourself before use!)
You can download a text version of edt_GetCellRect here
No comments:
Post a Comment