Moving of records inside a List with Drag and Drop

I have a special little project where I’ll have multiple lists and user will be able to drag and drop records between them. I’ve never done drag&drop but there’s cw manual and it seems simple.

However, when there are some records in any of the lists, the user must be able to grab any record inside any list and put it (drag it) anywhere in the list in order to rearrange the records in the list.
For example, he could grab a record in the list which appears on 5th place and drag it onto 2nd place.

Has anyone done anything like that? Clicking buttons (move up, move down) technique is not possible in this case, it has to be grab and move with a mouse. Much like when you rearrange controls in tab editor in windows designer for example…

I’d appreciate any instructions and tricks on how this can be done. Ideally it would be great if even when doing a drag and drop from list 1 to list 2, wherever the drop would happen (between records in list 2), the dropped records would land exactly there…



Not sure how to do what you are thinking but maybe this as an alternative…

When you right click on the list add a popup option to move highlighted record which select the record as “hot” then have the user click on another record in the list and the popup can be “Before / After / Cancel”

Or maybe even a “Cut / Paste” scenario where they “Cut” the highlighted record and then “paste” it “Before / After” newly highlighted record.

Just giving you other options. Yours sounds interesting - following…

NetTalk supports this in web mode, and the process shoukd be pretty straight-forward to code in desktop mode.

The key is in two parts;

A) make an ORDER field in your table as a REAL.
B) prime the field with arbitary values in existing records (ie so theyre not all 0).

Once you have this it becomes easy. Wherever you drop you take the order value before, add the one after, and divide by 2. Thats the new order value.

Having a “renumber” type function that takes all the related rows (all the line items on one invoice) and redistributes the numbers (to create big gaps netween them) from time to time does no harm, but its not really necessary.


when the record is “grabbed” (with mouseleft and hold) and moved inside the same list and then dropped, I can get back some info where I dropped it in the list? Like position or something?

Hey Bruce;

I thought Bostjan understood the database requirements (real divide by 2 etc), but was wanting a way to drag/drop a line w/in the same listbox and was looking for some type of event to say what line on the list was dropped on. I did not know of any so was suggesting a “non-button” solution since that is what he wanted. Though my answer was not exactly what he wanted i was offering other ways. Maybe I misunderstood.

Yes. look for PropList:MouseUpRow in the help.
It’s populated when the drop event occurs. (you’ll also find PropList:MouseDownRow which helps you with which row is being dragged.)

Change Prop: to PropList: for Mouse Up/Down props

See help topic: FORMAT() List Box Mouse Click Properties

Great - i tried looking but didn’t see it - hope he post his final result status to see if it is working. :smile:

I’ve wrote this decades ago, in my case I’m working with a tree.

  1. On your LIST set the DRAGID and the DROP to include the same ID
    ex: LIST,DRAGID('ThisQ', 'AnotherPlace'),DROPID('ThisQ')

  2. when EVENT() = EVENT:Drag

  ! GET( FromQ, ?List{PROPList:MouseDownRow)  ! see comments below by Jeff Slarve
    GET( FromQ, ?List{PROPList:MouseDownRow + 0)
    SETDROPID( 'PK=' & Q.PK )
  1. when EVENT() = EVENT:Drop
       DropRow = ?List{PROPList:MouseUpRow)
    IF DropRow > RECORDS( FromQ )
       DropRow = RECORDS( FromQ )
    ?List{PROP:Selected} = DropRow 

    DropString = DropID()
    ! parse DropString to get the PK
    ! make your change in the queue and underlying data
  1. Consider having a checkbox to control if you are allowing dragging
    as it can be easy to for a user to accidentally perform a drag
    When ACCEPTED() = ?UI:CanDrag
    IF UI:CanDrag
         ?List{PROP:DragID, 1} = 'ThisQ'
         ?List{PROP:DragID, 2} = 'AnotherPlace'
         ?List{PROP:DragID, 1} = '' 
1 Like

You’d probably want to surround that with INT() or add 0 instead of passing {PROPList:MouseDownRow} directly to GET()

Yeah, that was simplified from the original code
were I stored it in a LONG

Can you explain why using the property directly can be an issue

I think what happens is that it uses a different variant of GET(QUEUE) than GET(QUEUE,POINTER). I would assume it’s the (QUEUE,NAME) flavor.
But whatever is happening will test your sanity if you don’t know about it.

1 Like

A PROP: always returns a STRING Expression … even though many are 1=True it returns String ‘1’.

As Jeff said GET(Q, Parameter) is overloaded and uses the Type of Parameter so a STRING type would use the GET(Q,Name) not GET(Q, Pointer).

The workaround is coding GET( Q, 0 + ?List{PROPList:MouseDownRow) to force a Numeric Expression.