FOR EACH loControl IN laSelected amouseobj( laM, 1 ) loControl.Left = laM[3] && m.loControl.Left + m.lnHOffset loControl.Top = laM[4] &&m.loControl.Top + m.lnVOffset ENDFORI'm aware that it does not work well with more objects selected, but after some extra coding that should be doable also.
LPARAMETERS tlCopyHorizontally AS Boolean, tnSpacing AS Number >#IF .F. >PARAMETERS: > tlCopyHorizontally (O) - Indicates whether the new controls should be > copied and aligned to the right of the selected > controls. If omitted, defaults to .F., the > controls will be copied below the selected > controls. > tnSpacing (O) - Indicates how many pixels to leave between the > selected group of controls, and the new controls. > IF omitted, defaults to 5. > >USAGE: > ON KEY LABEL CTRL+K DO oxCopyCtrl WITH .F., 10 > >NOTES: > We experience a refresh problem with this routine. Although the > controls were being copied and repositioned correctly, they often > appeared to be cut off (so that only the top or left edge of the group > of controls could be seen). Clicking in the form seemed to correct this, > but it would be better if the display could be corrected programmatically. >#ENDIF > >*-- When controls are copied and pasted without using the mouse, >*-- the default position for the new controls is 8 pixels below >*-- and 8 pixels to the right of the position of the selected >*-- controls. >#DEFINE DEFAULT_LEFT_OFFSET 8 >#DEFINE DEFAULT_TOP_OFFSET 8 > >LOCAL laSelected[1], ; > loControl AS Container, ; > lnLeft, ; > lnRight, ; > lnTop, ; > lnBottom, ; > lnHOffset, ; > lnVOffset > >*-- Check if the user wants to copy the controls horizontally, rather >*-- than vertically. >tlCopyHorizontally = ( VARTYPE( m.tlCopyHorizontally ) = "L" ; > AND m.tlCopyHorizontally ) > >*-- If a numeric value for spacing was passed, use it, otherwise we'll >*-- default to 5 pixels. >tnSpacing = IIF( VARTYPE( m.tnSpacing ) = "N", INT( m.tnSpacing ), 5 ) > >*-- Initialize the position variables so that the first control that's >*-- processed will update these variables with it's values. >lnLeft = 1000000 >lnRight = -1000000 >lnTop = 1000000 >lnBottom = -1000000 > >*-- Populate an array with object references for all selected controls. >IF ASELOBJ( laSelected ) = 0 > *-- Nothing was selected, so there's nothing to do. > RETURN >ENDIF > >*-- Determine the outer boundaries for the group of controls. >FOR EACH loControl IN laSelected > lnLeft = MIN( m.lnLeft, m.loControl.Left ) > lnRight = MAX( m.lnRight, m.loControl.Left + m.loControl.Width ) > lnTop = MIN( m.lnTop, m.loControl.Top ) > lnBottom = MAX( m.lnBottom, m.loControl.Top + m.loControl.Height ) >ENDFOR > >*-- Clear this variable, just to make sure we don't leave behind any >*-- dangling object references. >loControl = .NULL. > >IF m.tlCopyHorizontally > *-- The controls are to copied horizontally (to the right), so the > *-- new controls need to be moved to the right by the total width of > *-- the selected *group* of controls, minus the distance to the right > *-- that the new controls will have already moved, plus the spacing > *-- that was specified. > lnHOffset = m.lnRight - m.lnLeft - DEFAULT_LEFT_OFFSET + m.tnSpacing > *-- Move the controls back up by the amount that they will have been > *-- moved down, so that they align vertically with the original > *-- controls. > lnVOffset = -1 * DEFAULT_TOP_OFFSET >ELSE > *-- Move the controls back to the left by the amount that they will > *-- have been moved to the right, so that they align horizontally with > *-- the original controls. > lnHOffset = -1 * DEFAULT_LEFT_OFFSET > *-- The controls are to copied vertically (down), so the new controls > *-- need to be moved down by the total height of the selected *group* > *-- of controls, minus the distance down that the new controls will > *-- have already moved, plus the spacing that was specified. > lnVOffset = m.lnBottom - m.lnTop - DEFAULT_TOP_OFFSET + m.tnSpacing >ENDIF > > > >*-- Flush the keyboard buffer, and copy the selected controls. >KEYBOARD '{MOUSE}' PLAIN CLEAR >SYS( 1500, "_MED_COPY", "_MEDIT" ) > >*-- We seem to need a pause here while the clipboard is being populated. >*-- A half-second worked well for me, but your results may vary. >WAIT WINDOW "" NOCLEAR TIMEOUT .5 > >*-- Flush the keyboard buffer again, and paste the copied controls. >KEYBOARD '{MOUSE}' PLAIN CLEAR >SYS( 1500, "_MED_PASTE", "_MEDIT" ) > >*-- A pause after the paste also seems to be needed. >WAIT WINDOW "" NOCLEAR TIMEOUT .5 > >*-- The controls that were just pasted will now be the selected controls. >*-- Get the object references for them into an array so that we can scan >*-- through and adjust the positions of the controls. >ASELOBJ( laSelected ) >FOR EACH loControl IN laSelected > loControl.Left = m.loControl.Left + m.lnHOffset > loControl.Top = m.loControl.Top + m.lnVOffset >ENDFOR > >*-- Mike Yearwood - Feb 21, 2006 >*-- Setting focus to anything on the form/class designer >*-- seems to remove the refreshing problems. >*!* m.loControl.Parent.SetFocus() > >*-- Mike Yearwood - March 12, 2006 >*-- Better yet, how about setting focus to the first >*-- control in the new set. >FOR EACH m.loControl IN laSelected > IF PEMSTATUS(m.loControl,"SETFOCUS",5) > m.loControl.SetFocus() > EXIT > ENDIF >ENDFOR EACH m.loControl > >*-- Clear this variable, just to make sure we don't leave behind any >*-- dangling object references. >loControl = .NULL.