1. Daniel Vivier
  2. PowerBuilder
  3. Saturday, 9 May 2020 14:28 PM UTC

Does anyone have any sample code or pointer to a helpful article for doing this - dragging one row of a listbox control to another position in the control and dropping it there, to re-order the items?

Thanks.

Daniel Vivier Accepted Answer Pending Moderation
  1. Monday, 11 May 2020 13:56 PM UTC
  2. PowerBuilder
  3. # 1

OK, now I have a working DataWindow solution based on a very simplified version of http://anvil-of-time.com/wordpress/powerbuilder/powerbuilder-datawindow-dragdrop-rows-with-business-rules/

I created a user object DW u_drag_dw. It has the DragIcon set to DataPipeline! (Maybe there are better options.)

The DataWindow to be inserted into it has to have a 1-char String column (not displayed) named row_drag, a horizontal line at the very top of the Detail area that is invisible, with a DW expression for Visible that is IF (row_drag = 'T',1,0), and a horizontal line at the very bottom of the Detail area that is invisible, with a DW expression for Visible that is IF ( row_drag = 'B',1,0). Those lines will appear as part of moving the mouse to show where you are dropping the row.

Declare this Local External Function:

SUBROUTINE SleepMs(ulong milliseconds) LIBRARY "kernel32.dll" Alias for "Sleep"

Declare these Instance variables:

boolean ib_drag, ib_mouse_down
long il_dragged_row, il_mouse_down_x, il_mouse_down_y

Clicked event script:

this.SelectRow(0, FALSE) // unselect all selected rows
this.SelectRow(row, TRUE) // select the clicked row
ib_drag = (row > 0) // are we capable of dragging?
il_dragged_row = row // source row which is dragged (used for visual indicator on dw)
IF ib_drag THEN
    ib_mouse_down = TRUE // button is clicked
    il_mouse_down_x = xpos // original coordinates of pointer
    il_mouse_down_y = ypos
ELSE
    ib_mouse_down = FALSE
END IF

Create event ue_dwnmousemove, mapped to pbm_dwnmousemove, with script:

IF ib_drag THEN // we are capable of being dragged
    IF ib_mouse_down THEN // mouse is down
        IF (Abs(PointerX() - il_mouse_down_x) > 50) OR (Abs(PointerY() - il_mouse_down_y) > 50) OR &
            (PointerX() = 0) OR (PointerY() = 0) THEN
            // we have moved the pointer more than 50 powerbuilder units so we are dragging the row
            Drag(Begin!)
        END IF
    END IF
END IF

DraggedWithin event script:

// scroll the datawindow if not all row fit
long l_i, ll_firstrow, ll_lastrow

ll_firstrow = long(this.Object.DataWindow.FirstRowOnPage)
ll_lastrow = long(this.Object.DataWindow.LastRowOnPage)

IF (row = ll_firstrow OR row = ll_firstrow + 1) AND ll_firstrow > 1 THEN
    this.ScrollPriorRow( )
    SleepMS(100) // don't scroll too fast!
ELSEIF (row = ll_lastrow OR row = ll_lastrow - 1) AND ll_lastrow < this.rowcount( ) THEN
    this.ScrollNextRow( )
    SleepMS(100)
END IF

// set the visual indicator for the drop location, by setting the column value that determines the
// visibility of the lines at the top and bottom of each row

FOR l_i = 1 TO this.RowCount()
    this.SetItem(l_i, "row_drag", " ")
NEXT
// set up for visual indicators
IF il_dragged_row > Row THEN
    this.SetItem(Row, "row_drag", "T")
    IF Row <> 1 THEN
        this.SetItem(Row - 1, "row_drag", "B")
    END IF
ELSE
    this.SetItem(Row, "row_drag", "B")
    IF Row <> this.RowCount() THEN
        this.SetItem(Row + 1, "row_drag", "T")
    END IF
END IF

Create event ue_lbuttonup, mapped to pbm_dwnlbuttonup, with script:

long l_i

ib_Mouse_Down = False
IF ib_drag THEN // are we dragging?
    ib_drag = False // stop dragging
    This.Drag(End!)
END IF
// reset the visual indicator on the datawindow
FOR l_i = 1 TO this.RowCount()
    this.SetItem(l_i, "row_drag", " ")
NEXT

DragDrop event script:

long ll_row, ll_beforerow

if source <> this then return

ll_row = GetSelectedRow(0) // should be same as il_dragged_row
IF ll_row = 0 THEN return
IF ll_row = row THEN return

if row > ll_row then
    ll_beforerow = row + 1
else
    ll_beforerow = row
end if
RowsMove(ll_row, ll_row, Primary!, this, ll_beforerow, Primary!)

ll_row = GetSelectedRow(0)
this.ScrollToRow(ll_row)

That's it! Place that object on a window, assign it a DataObject as explained above (with the row_drag column and the two lines), and it should just work. The one thing I don't like is that it is a bit flaky about scrolling at the top or bottom, you sometimes have to jiggle the position a bit before it really works. (I added the SleepMS calls to the code in the original article, because otherwise I found the whole DW scrolled at once, all the way to the top or bottom!)

 

Comment
There are no comments made yet.
Daniel Vivier Accepted Answer Pending Moderation
  1. Sunday, 10 May 2020 18:00 PM UTC
  2. PowerBuilder
  3. # 2

I got this to more less work with a ListView control (with no icons) with a variation of the instructions in the PB Help topic "Moving items using drag and drop", which is for TreeViews.

Create a ListView on a window. Set it to ListViewReport! View style, with ShowHeader turned off. (I suppose it would be OK with a header.) Turn on DragAuto in the Other properties, but don't select a DragIcon (which means it will show a replica of the item when dragging, which is good!).

After whatever code Adds the items to the ListView (or I guess if they are set in the painter), add the following line of code in the window, to make sure only one column of items shows:

lv_1.AddColumn("", Left!, lv_1.Width - 100) // if I don't subtract 100, I get a horizontal scroll bar I don't want

Add an int instance variable ii_dragged_index.

ListView BeginDrag script:

ii_dragged_index = index

ListView DragDrop script:

ListViewItem lvi_src

this.GetItem(ii_dragged_index, REF lvi_src)
if this.InsertItem(index + 1, lvi_src.Label, 1) = -1 then
    MessageBox("Error", "Internal error: Could not drop item.")
    return 0
else
    if ii_dragged_index > index then
        this.DeleteItem(ii_dragged_index + 1)
    else
        this.DeleteItem(ii_dragged_index)
    end if
end if

I did not include a version of the DragWithin script that that Help topic shows, which sets the DropHighlighted property on each item as you drag over it, because at least in my version of it, it left a bunch of items highlighted, and I saw no ListView API to turn off that highlighting. And it didn't seem necessary.

HOWEVER, the problem with this solution is that if you have more items than fit in the ListView (so there's a vertical scroll bar), dragging an item down to the bottom does not cause scrolling! So I can only drag to the bottom of the currently displayed items, then scroll the view, then drag the item some more. Not wonderful.

Comment
There are no comments made yet.
Daniel Vivier Accepted Answer Pending Moderation
  1. Saturday, 9 May 2020 15:55 PM UTC
  2. PowerBuilder
  3. # 3

I'm Googling and reading Help and starting to think this might be very difficult (to impossible) with a ListBox.

One option seems to be using a DW with a simplified version of the solution here:

http://anvil-of-time.com/wordpress/powerbuilder/powerbuilder-datawindow-dragdrop-rows-with-business-rules/

It also looks a bit like a ListView might work, using the same sort of techniques as the Help lists for a TreeView, in the Help topic you can find in the Index under "Moving items using drag and drop".

Thoughts? Thanks.

Comment
There are no comments made yet.
  • Page :
  • 1


There are no replies made for this question yet.
However, you are not allowed to reply to this question.