FiveTech Support Forums

FiveWin / Harbour / xBase community
Board index FiveWin for Harbour/xHarbour How to fire to change nArrayAt with nRow, nCol in Xbrowse.
Posts: 1387
Joined: Fri May 23, 2008 01:33 PM
How to fire to change nArrayAt with nRow, nCol in Xbrowse.
Posted: Fri Feb 06, 2026 02:10 PM

Hi

I have code like this.

	DragAcceptFiles( oDlg:hWnd, .T. )
	oDlg:oDragCursor	:= oCrs
	oDlg:bDropFiles:={|nRow,nCol,uDropInfo|Toplu_New_KASA_DragAll(nRow,nCol,uDropInfo, oBrw)}	
	
FUNCTION Toplu_New_KASA_DragAll(nRow,nCol,uDropInfo, oBrw)
	...... 
RETURN 0

How to selected item to change nArrayAt with nRow, nCol in Xbrowse?

Thanks.

Regards,



Hakan ONEMLI



Harbour & MSVC 2022 & FWH 23.06
Posts: 44158
Joined: Thu Oct 06, 2005 05:47 PM
Re: How to fire to change nArrayAt with nRow, nCol in Xbrowse.
Posted: Fri Feb 06, 2026 06:37 PM

You're asking how to convert mouse coordinates (nRow, nCol) from a drag-and-drop operation into the correct nArrayAt position in an XBrowse control, so you can select the item at the drop location. 0-cite-0

Answer

To select the item at the drop position in XBrowse, use the SetPos() method with the mouse coordinates. Here's the pattern:

Code (harbour): Select all Collapse
FUNCTION Toplu_New_KASA_DragAll(nRow, nCol, uDropInfo, oBrw)
   oBrw:SetPos(nRow, nCol, .t.)
   // Now oBrw:nArrayAt is set to the correct row
   // and oBrw:nColSel is set to the correct column
   
   // Your processing code here
   oBrw:Refresh()
RETURN 0

The SetPos(nRow, nCol, .t.) method converts pixel coordinates to the browse position and updates both nArrayAt (the array index) and nRowSel (the visible row position). 0-cite-1

Real Example from Codebase

The booking sample shows this exact pattern in action: 0-cite-2

Code (harbour): Select all Collapse
:bDropOver := <|u,r,c,f|
   oBrw:SetPos(r, c, .t.)
   oBrw:SelectedCol():Value := aData[u[1], u[2]]
   aData[u[1], u[2]] := 0
   XEval(oBrw:bChange, oBrw)
   oBrw:Refresh()
   return nil

After calling SetPos(), you can access:

  • oBrw:nArrayAt - the array index of the selected row
  • oBrw:nRowSel - the visible row position (1-based)
  • oBrw:nColSel - the column position
  • oBrw:SelectedCol() - the column object at the drop position

Notes

The bDropFiles codeblock receives coordinates relative to the window where drag began. 0-cite-3 Starting from FWH 18.04, additional parameters aPoint and oSourceWnd are also passed, where aPoint contains coordinates relative to the destination window. However, SetPos() handles the coordinate conversion automatically, so you can use either the original nRow, nCol or the newer aPoint values.

Wiki pages you might want to explore:

Citations

File: source/classes/window.prg (L1340-1351)

Code (text): Select all Collapse
METHOD DropFiles( hDrop ) CLASS TWindow

   local aCoors := { 0, 0 }

   if ! Empty( ::bDropFiles )
      DragQueryPoint( hDrop, aCoors )
      Eval( ::bDropFiles, aCoors[ 2 ], aCoors[ 1 ], DragQueryFiles( hDrop ) )
   endif

   DragFinish( hDrop )

return nil

File: samples/misc/booking.prg (L75-86)

Code (text): Select all Collapse
      :bDragBegin    := < |r,c,f|
                           SetDropInfo( { oBrw:nArrayAt, oBrw:SelectedCol():nArrayCol } )
                           return nil
                           >
      :bDropOver     := < |u,r,c,f|
                           oBrw:SetPos( r, c, .t. )
                           oBrw:SelectedCol():Value := aData[ u[ 1 ], u[ 2 ] ]
                           aData[ u[ 1 ], u[ 2 ] ] := 0
                           XEval( oBrw:bChange, oBrw )
                           oBrw:Refresh()
                           return nil
                        >

File: whatsnew.txt (L5671-5680)

Code (text): Select all Collapse
* Drag and Drop Simplification: Till ver.18.04, bDropInfo was evaluated
  with 4 params:
  Eval( ::bDropOver, uDropInfo, nRow, nCol, nFlags )
  nRow and nCol are relative to the window from which the drag began.
  The destination windows needs to convert nRow,nCol to coordinates 
  relative to itself, without even knowing the source window.
  Now, bDropOver is evaluated with two more additional paramters.
  Eval( ::bDropOver, uDropInfo, nRow, nCol, nFlags, aPoint, oSourceWnd )
  aPoint is { nRow, nCol } relative to the destination window.
  oSourceWnd is the window where the drag began.
regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 1387
Joined: Fri May 23, 2008 01:33 PM
Re: How to fire to change nArrayAt with nRow, nCol in Xbrowse.
Posted: Fri Feb 06, 2026 09:27 PM

Hi Antonio, Thank you very much for your answer, but unfortunately the ::SetPos method doesn't do what I want.

Looking at the Xbrowse method, it seems the ::HeaderHeight() method is performing more calculations than it should (nDataRows), which is why it's being assigned 0 in the MouseRowPos method.

How Can i fix this?

Thanks.

Regards,



Hakan ONEMLI



Harbour & MSVC 2022 & FWH 23.06
Posts: 44158
Joined: Thu Oct 06, 2005 05:47 PM
Re: How to fire to change nArrayAt with nRow, nCol in Xbrowse.
Posted: Sat Feb 07, 2026 05:04 AM

You're asking about an issue with TXBrowse::MouseRowPos() returning 0 because ::nDataRows is being calculated incorrectly, which you suspect is related to ::HeaderHeight() performing extra calculations.

The Problem

Looking at the MouseRowPos() method, it calculates the row position from pixel coordinates and returns 0 if the calculated position exceeds ::nDataRows: 1-cite-0

Code (harbour): Select all Collapse
METHOD MouseRowPos( nRow ) CLASS TXBrowse
   local nRowPos, nTmp
   
   if nRow <= ::FirstRow()
      return 0
   endif
   
   nTmp    := nRow - ::FirstRow()
   nRowPos := Int( nTmp / ::nRowHeight ) + 1
   
   if nRowPos > ::nDataRows
      nRowPos := 0
   endif
   
return nRowPos

The issue is that ::nDataRows is calculated during the Adjust() method and depends on ::HeaderHeight() and ::FooterHeight(): 1-cite-1

Code (harbour): Select all Collapse
METHOD RowCount() INLINE ( If( ::nRowHeight == nil, ::Adjust(),), Int( ( ::BrwHeight() - ::FirstRow() - ::FooterHeight() ) / ::nRowHeight ) )

The Root Cause

The HeaderHeight() method includes additional height when lFull parameter is .t., adding ::nGetBarHeight if ::nBarHdr > 0: 1-cite-2

Code (harbour): Select all Collapse
METHOD HeaderHeight( lFull ) INLINE If( ::lHeader, IfNil( ::nHeaderHeight, 0 ) + ::nTopBarHeight + ;
      If( lFull == .t. .and. ::nBarHdr > 0, IfNil( ::nGetBarHeight, 0 ), 0 ), ;
   If( ::lDrawBorderIn, 1, 0 ) )

When MouseRowPos() calls ::FirstRow(), which in turn calls ::HeaderHeight(.t.), it includes the extra bar height: 1-cite-3

However, ::nDataRows is calculated based on the browse height minus the full header height, which may not match what MouseRowPos() expects.

The Fix

The issue is that ::nDataRows needs to be recalculated when the browse is adjusted. Looking at the Adjust() method, ::nDataRows should be set after all height calculations are complete: 1-cite-4

Solution: Ensure ::nDataRows is properly calculated by calling ::RowCount() after the browse is fully adjusted. In your drag-and-drop handler, you can force a recalculation:

Code (harbour): Select all Collapse
FUNCTION Toplu_New_KASA_DragAll(nRow, nCol, uDropInfo, oBrw)
   local nRowPos
   
   // Ensure browse is adjusted
   if oBrw:nRowHeight == nil
      oBrw:Adjust()
   endif
   
   // Calculate row position manually
   nRowPos := oBrw:MouseRowPos(nRow)
   
   if nRowPos > 0
      // Move to the calculated row
      oBrw:Skip(nRowPos - oBrw:nRowSel)
      oBrw:nRowSel := nRowPos
      oBrw:Refresh()
   endif
   
RETURN 0

Alternatively, if MouseRowPos() consistently returns 0, you can calculate the position directly:

Code (harbour): Select all Collapse
FUNCTION Toplu_New_KASA_DragAll(nRow, nCol, uDropInfo, oBrw)
   local nRowPos, nTmp
   
   if nRow > oBrw:FirstRow()
      nTmp := nRow - oBrw:FirstRow()
      nRowPos := Int(nTmp / oBrw:nRowHeight) + 1
      
      if nRowPos <= oBrw:RowCount()
         oBrw:Skip(nRowPos - oBrw:nRowSel)
         oBrw:nRowSel := nRowPos
         oBrw:Refresh()
      endif
   endif
   
RETURN 0

Notes

The ::nDataRows data member is marked as "used internally" and is supposed to hold the actual number of visible data rows. 1-cite-5 It's calculated during painting and adjustment phases. If you're experiencing issues with MouseRowPos() returning 0, it's likely that ::nDataRows hasn't been properly initialized yet, which typically happens on the first paint cycle. Calling oBrw:Adjust() or oBrw:Refresh() before processing the drop should resolve this.

Wiki pages you might want to explore:

Citations

File: source/classes/xbrowse.prg (L251-251)

Code (text): Select all Collapse
      nDataRows,;     // Actual number of data rows, used internally

File: source/classes/xbrowse.prg (L768-770)

Code (text): Select all Collapse
   METHOD HeaderHeight( lFull ) INLINE If( ::lHeader, IfNil( ::nHeaderHeight, 0 ) + ::nTopBarHeight + ;
         If( lFull == .t. .and. ::nBarHdr > 0, IfNil( ::nGetBarHeight, 0 ), 0 ), ;
      If( ::lDrawBorderIn, 1, 0 ) )

File: source/classes/xbrowse.prg (L774-774)

Code (text): Select all Collapse
   METHOD RowCount()     INLINE ( If( ::nRowHeight == nil, ::Adjust(),), Int( ( ::BrwHeight() - ::FirstRow() - ::FooterHeight() ) / ::nRowHeight ) )

File: source/classes/xbrowse.prg (L776-776)

Code (text): Select all Collapse
   METHOD FirstRow()     INLINE ::HeaderHeight( .t. )

File: source/classes/xbrowse.prg (L1441-1469)

Code (text): Select all Collapse
   endif
   ::nHeaderPad := ::nFooterPad := 0

   if ::lAdjusted .and. ::lFitGridHeight .and. ;
         ( ( ::lHeader .and. ::nHeaderHeight > 1 ) .or. ::lFooter )

      if ( nGap  := ::DataRect:nHeight % ::nRowHeight ) > 0

         if ::lHeader .and. ::nHeaderHeight > 1
            if ::lFooter
               ::nFooterPad   := Int( nGap * ::nFooterHeight / ( ::nHeaderHeight + ::nFooterHeight ) )
               ::nHeaderPad   := nGap - ::nFooterPad

               //                ::nFooterHeight   += ::nHeaderPad // bug fixed 2018-07-10
               //                ::nHeaderHeight   += ::nFooterPad

               ::nFooterHeight   += ::nFooterPad   // bug fixed 2018-07-10
               ::nHeaderHeight   += ::nHeaderPad

            else
               ::nHeaderHeight   += ( ::nHeaderPad := nGap )
            endif
         else
            ::nFooterHeight   += ( ::nFooterPad := nGap )
         endif
      endif
   endif

return Self

File: source/classes/xbrowse.prg (L4716-4731)

Code (text): Select all Collapse
      METHOD MouseRowPos( nRow ) CLASS TXBrowse

         local nRowPos, nTmp

         if nRow <= ::FirstRow()
            return 0
         endif

         nTmp    := nRow - ::FirstRow()
         nRowPos := Int( nTmp / ::nRowHeight ) + 1

         if nRowPos > ::nDataRows
            nRowPos := 0
         endif

      return nRowPos
regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 1387
Joined: Fri May 23, 2008 01:33 PM
Re: How to fire to change nArrayAt with nRow, nCol in Xbrowse.
Posted: Sat Feb 07, 2026 09:14 AM

Hi Antonio,

My xbrowse len is 3. ::nDataRows is calculated right.

::HeaderHeight(.t.) is incorrect. It calculates the result as 5, so it reduces it to 0.

Regards,



Hakan ONEMLI



Harbour & MSVC 2022 & FWH 23.06
Posts: 44158
Joined: Thu Oct 06, 2005 05:47 PM
Re: How to fire to change nArrayAt with nRow, nCol in Xbrowse.
Posted: Sun Feb 08, 2026 05:40 AM

You're reporting that ::HeaderHeight(.t.) is returning 5 when it should return a smaller value, causing MouseRowPos() to incorrectly return 0 because the calculated row position appears to be before the first data row.

The Problem

The issue is that ::HeaderHeight(.t.) includes extra height from ::nGetBarHeight when ::nBarHdr > 0: 2-cite-0

Code (harbour): Select all Collapse
METHOD HeaderHeight( lFull ) INLINE If( ::lHeader, IfNil( ::nHeaderHeight, 0 ) + ::nTopBarHeight + ;
      If( lFull == .t. .and. ::nBarHdr > 0, IfNil( ::nGetBarHeight, 0 ), 0 ), ;
   If( ::lDrawBorderIn, 1, 0 ) )

When lFull is .t. and ::nBarHdr > 0, it adds ::nGetBarHeight to the header height. Since ::FirstRow() calls ::HeaderHeight(.t.), this inflates the starting position for data rows. 2-cite-1

In MouseRowPos(), when you subtract this inflated ::FirstRow() value from nRow, you get a smaller or negative nTmp, which then calculates to row position 0 or 1, and if your browse only has 3 rows (::nDataRows = 3), valid positions are 1-3. 2-cite-2

The Solution

Option 1: Bypass MouseRowPos() and calculate directly

Since MouseRowPos() is having issues with the header height calculation, calculate the row position yourself without relying on ::FirstRow():

Code (harbour): Select all Collapse
FUNCTION Toplu_New_KASA_DragAll(nRow, nCol, uDropInfo, oBrw)
   local nRowPos, nTmp
   local nActualHeaderHeight
   
   // Use the base header height without the bar height
   nActualHeaderHeight := oBrw:HeaderHeight()  // Call without .t. parameter
   
   if nRow > nActualHeaderHeight
      nTmp := nRow - nActualHeaderHeight
      nRowPos := Int(nTmp / oBrw:nRowHeight) + 1
      
      if nRowPos > 0 .and. nRowPos <= oBrw:nDataRows
         oBrw:nRowSel := nRowPos
         oBrw:Refresh()
      endif
   endif
   
RETURN 0

Option 2: Check if ::nBarHdr is incorrectly set

The extra height is only added when ::nBarHdr > 0. Check if this value is being set when it shouldn't be. You can temporarily disable it:

Code (harbour): Select all Collapse
FUNCTION Toplu_New_KASA_DragAll(nRow, nCol, uDropInfo, oBrw)
   local nRowPos, nSaveBarHdr
   
   nSaveBarHdr := oBrw:nBarHdr
   oBrw:nBarHdr := 0  // Temporarily disable bar height
   
   nRowPos := oBrw:MouseRowPos(nRow)
   
   oBrw:nBarHdr := nSaveBarHdr  // Restore
   
   if nRowPos > 0
      oBrw:nRowSel := nRowPos
      oBrw:Refresh()
   endif
   
RETURN 0

Notes

The ::nGetBarHeight is initialized during Adjust() to FontHeight() + 8 2-cite-3 , and the ::nBarHdr value controls whether this extra height is included in the full header calculation. The painting code also uses ::FirstRow() which includes this extra height 2-cite-4 , so the visual layout should match. If MouseRowPos() is returning 0, it suggests the mouse coordinates you're receiving in bDropFiles might not be relative to the browse window itself, or ::nBarHdr is set when your browse doesn't actually have a bar area.

Wiki pages you might want to explore:

Citations

File: source/classes/xbrowse.prg (L768-770)

Code (text): Select all Collapse
   METHOD HeaderHeight( lFull ) INLINE If( ::lHeader, IfNil( ::nHeaderHeight, 0 ) + ::nTopBarHeight + ;
         If( lFull == .t. .and. ::nBarHdr > 0, IfNil( ::nGetBarHeight, 0 ), 0 ), ;
      If( ::lDrawBorderIn, 1, 0 ) )

File: source/classes/xbrowse.prg (L776-776)

Code (text): Select all Collapse
   METHOD FirstRow()     INLINE ::HeaderHeight( .t. )

File: source/classes/xbrowse.prg (L1579-1579)

Code (text): Select all Collapse
   DEFAULT ::nGetBarHeight   := FontHeight( Self, IfNil( ::oFont, ::oWnd:oFont ) ) + 8

File: source/classes/xbrowse.prg (L2419-2419)

Code (text): Select all Collapse
      nFirstRow   := ::FirstRow()

File: source/classes/xbrowse.prg (L4716-4731)

Code (text): Select all Collapse
      METHOD MouseRowPos( nRow ) CLASS TXBrowse

         local nRowPos, nTmp

         if nRow <= ::FirstRow()
            return 0
         endif

         nTmp    := nRow - ::FirstRow()
         nRowPos := Int( nTmp / ::nRowHeight ) + 1

         if nRowPos > ::nDataRows
            nRowPos := 0
         endif

      return nRowPos
regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 1387
Joined: Fri May 23, 2008 01:33 PM
Re: How to fire to change nArrayAt with nRow, nCol in Xbrowse.
Posted: Sun Feb 08, 2026 10:37 AM

Hi Antonio,

In my case, the solution was to use - ::nTop. Just so you know.

METHOD MouseRowPos( nRow ) CLASS TXBrowse

   local nRowPos, nTmp

   if nRow <= ::FirstRow()
      return 0
   endif

   nTmp    := nRow - ::FirstRow() - ::nTop     <-------- Added - ::nTop
   nRowPos := Int( nTmp / ::nRowHeight ) + 1

   if nRowPos > ::nDataRows
      nRowPos := 0
   endif

return nRowPos

Thank you.

Regards,



Hakan ONEMLI



Harbour & MSVC 2022 & FWH 23.06

Continue the discussion