I asked about moving a list box and several replied with helpful
information.  Without their help, I would not have been able to make this
work.

  The opportunity to overcome that I had with all of the suggestions was
that letting the system know the mouse was being handled (by returning true
in the mousedown event) shut down all other mouse actions on that list box.
That was "Not a Good Thing" (NAGT).  The solution lies in using a baby state
machine and a timer.

  I finally got it to work the way I wanted,  so I'll share this with other
possible newbies.

  I wanted to pop up a menu and select the "Move" feature.  I then wanted
to click on a list box and
drag it when the "Move" feature was selected.  I also wanted to be able to
select a cell and select Edit

 I also wanted this to show up on all list boxes that I was dynamically
entering into a panel.


  Here is what I ended up with, and the functionality:

 User clicks on cell.  Cell is selected.  User Right clicks on list box.
ConstructContextMenu is fired and when item is selected,
ContextualMenuAction is fired.  The "DraggingStarting" field in the
DragHelper structure is set to true.  The system now waits for  a mouse
click on the list box.  If the click occurs, then the MouseDown event for
the listbox is fired, and since DraggingStarting is true, it captures the
current listbox position. It sets the state machine to the second state,
that of DraggingStarted, and clears DraggingStarting.  It then returns true
so that the system allows the next click in the listbox to be the drag event
you want to handle.  When mousedown returns true, it lets the drag
commence.  The drag event sees that DraggingStarted is true, and handles the
drag (This may be redundant, but fits with the design's purpose of allowing
new code not to interfere with future or past code).

 The Timer looks at the DraggingStarted.  Once it sees it is set, it
monitors for MouseUp.  Once MouseUp occurs, it resets DraggingStarted and
turns itself off to conserve system resources.  The listbox is now locked in
place.

  With this state machine approach, other mouse click activites can be
added without stepping on existing code (including cell to cell dragging).
------------------------------------------------------------------------------------------------------------------------------------------

 1.  Drop a list box on a panel.  Set its index to 0.  Make it invisible.
Set its name to ListBoxObj
     Add a property, ListBoxes(1,1)   as ListBoxObj    // I had this on a
panel set, so I used a 2 dimensional array

     Add the following code in the window Open routine

  dim i,j,r as Integer
   j = UBound( ListBoxes  , 2)
   i = UBound(ListBoxes,1)
  Redim ListBoxes(i+1,j+1)  // used so I could repeat as often as I wish in
the future
   ListBoxes(0,0)   = new ListBoxObj

   ListBoxes(0,0).Visible = true
  // ListBoxes(0,0).PanelIndex = 0  // put on panel 1 for my window.  leave
out for your single window test
   ListBoxes(0,0).Top = 20
   ListBoxes(0,0).Left = 20
//----------------------------------------------
 2.  Create a module.  I called mine Global, as I was putting global
variables into it (such as version and other stuff)
 3.  Create a Structure called DragHelperStruct.  Create structure members
localX, localY as integers, DragStarting, DragStarted as Booleans
 4.  Add a Property to Global,  DragHelper as DragHelperStruct
 4a. (optional)  Add a property to Global, DraggedList as Listbox   (this
can be used to run code against listbox in the timer routine if you need,
for instance, allowing a click outside the listbox to cancel the drag
event.)
5.  Add a Timer to your window, called Timer1  (maybe call it DragTimer in
the future?), set its period to 10  (or 20, but less than 100 for
responsiveness)

6. In the ListBoxObj, ConstructContextualMenu method, add the following
code  (This does the popup menu.  Took forever for me to find this code in
the language reference!)

 dim m1 as New MenuItem
 dim m2 as New MenuItem

 m1.Text = "Move"
 m2.Text = "Edit"

 base.Append(m1)
 base.Append(m2)

 return true //  lets the system know a context menu is working
//----------------------------
 7.  In the ListBoxObj, ContextualMenuAction method, add the following
code:

 Select Case hitItem.Text
 case "Move"
  // Global.DraggedList = me  // not used now, but could be used for other
things in the future. uncomment to use
   Global.DragHelper.DragStarting = True
   Timer1.Enabled = true


 Case "Edit"
   // do nothing for now
 end Select

 return True // finished
//----------------------------
 8.  In the  ListBox MouseDown method, add the following code:
 if (Global.DragHelper.DragStarting) then
   Global.DragHelper.LocalX = X
   Global.DragHelper.LocalY = Y
   Global.DragHelper.DragStarting = False
   Global.DragHelper.DragStarted = True
   return true  // only return true if we are really going to drag
 end if
//----------------------------
9.  In the ListBox MouseDrag method, add the following code:

 if (Global.DragHelper.DragStarted) then
   me.Left = me.Left + (X - Global.DragHelper.LocalX)
   me.top = me.Top +(Y - Global.DragHelper.LocalY)
 end if
//----------------------------

10.  In the Timer1 Action, add the following code:
 //--------------------------------------------------
 //      if Dragging is true then
 //  if mouse is up then
 //   disable timer
 //  set dragging false
 // end if

 if (Global.DragHelper.DragStarted) then
   if (System.MouseDown = False) then
     me.Enabled = False
     Global.DragHelper.DragStarted = False
   end if
 end if



Side Effect:  Global.DraggedList (if used) will have the last listbox that
had it's move menu selected.
_______________________________________________
Unsubscribe or switch delivery mode:
<http://www.realsoftware.com/support/listmanager/>

Search the archives of this list here:
<http://support.realsoftware.com/listarchives/lists.html>

Reply via email to