Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Drag and drop in a grid 1

Status
Not open for further replies.

Nro

Programmer
May 15, 2001
337
CA
Hello
I’ve made some search, but I did not find anything on that subject.

1 – I have a table with 10 columns, 10 lines. Each field is a memo type (Aa_Mem01, Aa_Mem02, Aa_Mem03...)
2 – I have a grid to display my 10 columns X 10 lines.
3 – I created a container class, with one edit box and one command button. (cntInput). When I bind the grid with the data source, I assign the container class to each column ;

Code:
lnMii = 1
FOR EACH loCol IN .Objects
     loCol.NewObject('cntInput','Invh_cntHoraire', COU_CLSINVHHOR,'')
     loCol.CurrentControl = 'cntInput'
     loCol.Sparse = .F.

     loCol.cntInput.edtRemark.ControlSource = .RecordSource + ".Aa_Mem" + PADL(ALLTRIM(STR(lnMii)),2,"0")

     BINDEVENT(loCol,"Resize",loCol.cntInput,"Set_ColumnWidth")

     lnMii = lnMii + 1

NEXT
Everything is working as expected. The memo data appear in the edit box, and if I click on my button, I show a form for data input.

My question: Is it possible to allow the user to drag one memo from one cell to an other?

Thanks in advance

Nro
 
It should be possible. I strongly recommend you look at OLE drag and drop rather than VFP's native drag and drop. It gives you a lot more control over the process.

Tamar
 
Hello

Yes Tamar. I'd try OLE drag for forms or lists (thanks for Hacker's Guide), but never for a grid.

In some test I did, if I drag an object over a grid, the OLEDragOver fires. I can retrieve the nXCoord and nYCoord.

It’s ok for a form, because you can retrieve the nXCoord and nYCoord to move the dragged object where you want.

But for a grid, I have to know the column and the record where the object is dragged over. Before starting tests and research, I want to know if it’s possible to achieve that.

If I can track the line/column where the object is dropped, it’s a good starting point.

Thanks in advance

Nro
 
Here is one of my test codes (within a TV and TV to Grid):
Code:
oForm = Createobject('myForm')
oForm.Show(1)

Define Class myForm As Form
  Height = 300
  Width = 470
  DoCreate=.T.
  DataSession=2
  nxtwips = .F.
  nytwips = .F.

  Add Object myTree As OleControl With ;
    Top = 0, ;
    Left = 0, ;
    Height = 300, ;
    Width = 200, ;
    Name = "myTree", ;
    OleClass = 'MSComCtlLib.TreeCtrl'

  Add Object myGrid As myGrid With ;
    Top = 0, ;
    Left = 220, ;
    Height = 300, ;
    Width = 250, ;
    Name = "myGrid"

  Procedure pixeltotwips
    *-- Code for PixelToTwips method
    Local liHWnd, liHDC, liPixelsPerInchX, liPixelsPerInchY
    #Define cnLOG_PIXELS_X 88
    #Define cnLOG_PIXELS_Y 90
    #Define cnTWIPS_PER_INCH 1440

    * Declare some Windows API functions.
    Declare Integer GetActiveWindow In WIN32API
    Declare Integer GetDC In WIN32API Integer iHDC
    Declare Integer GetDeviceCaps In WIN32API Integer iHDC, Integer iIndex

    * Get a device context for VFP.
    liHWnd = GetActiveWindow()
    liHDC = GetDC(liHWnd)

    * Get the pixels per inch.
    liPixelsPerInchX = GetDeviceCaps(liHDC, cnLOG_PIXELS_X)
    liPixelsPerInchY = GetDeviceCaps(liHDC, cnLOG_PIXELS_Y)

    * Get the twips per pixel.
    Thisform.nxtwips = ( cnTWIPS_PER_INCH / liPixelsPerInchX )
    Thisform.nytwips = ( cnTWIPS_PER_INCH / liPixelsPerInchY )
    Return
  Endproc

  Procedure Load
    Create Cursor myTest (myID i, myType c(20))
    For ix = 1 To 20
      Insert Into myTest (myID,myType) Values (ix,Sys(2015))
    Endfor
    Locate
    This.pixeltotwips()
  Endproc

  Procedure myTree.Init
    #Define tvwFirst	0
    #Define tvwLast	1
    #Define tvwNext	2
    #Define tvwPrevious	3
    #Define tvwChild	4

    With This
      .linestyle =1
      .labeledit =1
      .indentation = 5
      .PathSeparator = '\'
      .Scroll = .T.
      .OLEDragMode = 1
      .OLEDropMode = 1

      For ix=1 To 3
        .Nodes.Add(,tvwFirst,"root"+Ltrim(Str(ix)),'Main node '+Ltrim(Str(ix)))
        For jx=1 To 4
          .Nodes.Add("root"+Ltrim(Str(ix)),tvwChild,;
            "child"+Ltrim(Str((ix-1)*4+jx)),;
            'Child '+Ltrim(Str(jx))+' of '+Ltrim(Str(ix)))
        Endfor
      Endfor
    Endwith
  Endproc

  Procedure myTree.MouseDown
    *** ActiveX Control Event ***
    Lparameters Button, Shift, x, Y
    With Thisform
      oHitTest = This.HitTest( x * .nxtwips, Y * .nytwips )
      If Type("oHitTest")= "O" And !Isnull(oHitTest)
        This.SelectedItem = oHitTest
      Endif
    Endwith
    oHitTest = .Null.
  Endproc

  Procedure myTree.OLEDragOver
    *** ActiveX Control Event ***
    Lparameters Data, effect, Button, Shift, x, Y, state
    oHitTest = This.HitTest( x * Thisform.nxtwips, Y * Thisform.nytwips )
    If Type("oHitTest")= "O"
      This.DropHighlight = oHitTest
      If !Isnull(oHitTest)
        If Y <= This.Top + 150 	And Type('oHitTest.Previous')='O'	 And !Isnull(oHitTest.Previous)
          oHitTest.Previous.EnsureVisible
        Endif
        If Y >= This.Top + This.Height - 150 And Type('oHitTest.Next')='O' And !Isnull(oHitTest.Next)
          oHitTest.Next.EnsureVisible
        Endif
      Endif
    Endif
  Endproc

  Procedure myTree.OLEDragDrop
    *** ActiveX Control Event ***
    Lparameters Data, effect, Button, Shift, x, Y
    #Define tvwChild	4
    With This
      If Data.GetFormat(1)	And ;
          type(".DropHighLight") = "O" And !Isnull(.DropHighlight) &&CF_TEXT
        loTarget = .DropHighlight
        .Nodes.Add(loTarget.Key,tvwChild,;
          Sys(2015),;
          Data.GetData(1))
      Endif
    Endwith
    This.DropHighlight = .Null.
  Endproc
Enddefine

Define Class myGrid As Grid
  OLEDropMode = 1
  OLEDragMode = 1

  Procedure OLEStartDrag
    Lparameters oDataObject, nEffect
    With This
      .OLEDropMode = 0
      Amouseobj(arrMouse,1)
      lnActiveRow = Ceiling( ;
        ( arrMouse[4] - (.Top + .HeaderHeight) ) / .RowHeight )
      .ActivateCell(lnActiveRow,2)
    Endwith
    oDataObject.SetData(myTest.myType,1)
  Endproc

  Procedure OLECompleteDrag
    Lparameters nEffect
    This.OLEDropMode = 1
  Endproc

  Procedure OLEDragOver
    Lparameters oDataObject, nEffect, nButton, nShift, nXCoord, nYCoord, nState
    Local nWhere,nRelRow,nRelCol,nView
    Store 0 To nWhere,nRelRow,nRelCol,nView
    This.GridHitTest(m.nXCoord,m.nYCoord,@nWhere,@nRelRow,@nRelCol,@nView)
    If m.nWhere = 3
      This.ActivateCell(m.nRelRow, m.nRelCol)
    Endif
  Endproc

  Procedure OLEDragDrop
    Lparameters oDataObject, nEffect, nButton, nShift, nXCoord, nYCoord
    If oDataObject.GetFormat(1)
      With This
        .Columns(2).Text1.Value = oDataObject.GetData(1)
      Endwith
    Endif
  Endproc
Enddefine



Cetin Basoz
MS Foxpro MVP, MCP
 
Ok
I think I found something useful to determine the Column and Row in a grid. In OLEDragDrop method, I put this code (from MS knowledge base Q141636)
Code:
WITH THIS
 
 * Check destination grid for DeleteMark and RecordMark
 lnGridLeftWall = 1 + .Left + IIF(.DeleteMark and .RecordMark,18, ;
	IIF(.DeleteMark OR .RecordMark,9,0))
 
 * Check destination grid for Vertical Scroll bar
 lnGridRightWall = .Left + .Width  -IIF(.ScrollBars>1,14,0)
 
 * Check destination grid for Horizontal Scroll bar
 lnGridBottomEdge = .Top + .Height - IIF(.ScrollBars=1 OR ;
	.ScrollBars=3, 12 ,0)
 
 * Hold sum of ColumnWidths of columns to left of current column
 lnPrevColwidths = 0

 * Find out which destination row
 lnRowlevel = CEILING((nYcoord - .Top - ;
	.HeaderHeight) / .RowHeight)

 * Necessary if grid RecordSource table is not currently selected
 SELECT EVALUATE('THIS.RecordSource')
 
 * Loop through all visible columns
 FOR lnMi = .LeftColumn TO .ColumnCount
  
  * Determine if current column is drop destination
  IF BETWEEN(nXCoord, lnGridLeftwall + lnPrevColWidths, lnGridLeftwall + ;
         lnPrevColwidths + THIS.Columns(lnMi).Width) AND lnRowlevel > 0 AND ;
            nYCoord < lnGridBottomEdge AND nXCoord < lnGridRightWall
   
   * If correct column, call DragDrop of textbox in the column
   WAIT WINDOW "Column Name : " + ;
	THIS.Columns(lnMi).Name + " -> " + ;
	THIS.Columns(lnMi).ControlSource + ;
	" RowLevel : " + TRANSFORM(lnRowlevel ,"99999") NOWAIT	
    
   *THIS.Columns(lnMi).Text1.DragDrop(oSource,0,nYCoord, lnMi+1-THIS.LeftColumn,nRowlevel)
 
   EXIT       && After drop, no need to check additional columns
  
  ENDIF
  
  * Add width of current column to sum of widths of previous columns
  * and proceed to calculate if next column is drop destination
  lnPrevColWidths = lnPrevColWidths + .Columns(lnMi).Width
  
 NEXT
ENDWITH
Now I have the source field and the row. It’s a good start.

Thanks for your help and insight.
Nro
 
Is there a reason that you wouldn't use GridHitTest. That code was needed before GridHitTest available (VFP5 and before as I remember).

I forgot to say that from Grid to TV part actually use a similar method (nothing surprising, originally wrote it in VFP5 days:)

Cetin Basoz
MS Foxpro MVP, MCP
 
Hello Cetin.

You are right. I resolve my problem with GridHitTest. Now the user can drag and drop any cell to and other, very easily.

Thanks again for your great help.

Nro
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top