Introduction
I have come across many queries on 'how to make a control on a dialog movable' and 'how to make a group of controls movable at runtime'. Here is an attempt to achieve the same, in its simplest form; however, this can be molded as per requirements.
Background
As per Windows predefined behavior, we can move the dialog/frame windows at runtime using their caption/title bar. There can be instances when you want to move a control/a group of controls which do not have a title/caption bar. The sample code here addresses that.
Using the code
The code is written and compiled using Microsoft Visual Studio 6.0.
Use the Dialog Layout Editor of Windows to place the controls on a dialog.
You can associate the member variables as per your requirement, with these controls:
CStatic m_staticMovable;
CEdit m_editMovable;
Define additional member variables in the class CMovableTrialDlg
.
bool m_bMoving;
Please include PreTranslateMessage()
in your code.
virtual BOOL PreTranslateMessage(MSG* pMsg);
PreTranslateMessage()
performs the required action for the controls which are required to be moved.
BOOL CMovableTrialDlg::PreTranslateMessage(MSG* pMsg)
{
if(pMsg->hwnd == m_editMovable.m_hWnd)
{
if(pMsg->message == WM_LBUTTONUP)
{
OnMovableStaticLButtonUp(pMsg);
}
if(pMsg->message == WM_LBUTTONDOWN)
{
OnMovableStaticLButtonDown(pMsg);
}
if(pMsg->message == WM_MOUSEMOVE)
{
OnMovableStaticMouseMove(pMsg);
}
}
return CDialog::PreTranslateMessage(pMsg);
}
While the mouse moves and the status for moving the windows, m_bMoving
, is true
, perform the movement by changing the window placement for the controls.
void CMovableTrialDlg::OnMovableStaticMouseMove(MSG* pMsg)
{
if(m_bMoving == false)
return;
WINDOWPLACEMENT wp;
::GetWindowPlacement(m_editMovable.m_hWnd, &wp);
int nXDiff = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
int nYDiff = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
POINT pt = pMsg->pt;
ScreenToClient(&pt);
wp.rcNormalPosition.left = pt.x - 5;
wp.rcNormalPosition.top = pt.y - 5;
wp.rcNormalPosition.right = wp.rcNormalPosition.left + nXDiff;
wp.rcNormalPosition.bottom= wp.rcNormalPosition.top + nYDiff;
::SetWindowPlacement(m_editMovable.m_hWnd, &wp);
::GetWindowPlacement(m_staticMovable.m_hWnd, &wp);
nXDiff = wp.rcNormalPosition.right - wp.rcNormalPosition.left;
nYDiff = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top;
pt = pMsg->pt;
ScreenToClient(&pt);
wp.rcNormalPosition.left = pt.x - 5;
wp.rcNormalPosition.top = pt.y - nYDiff - 5;
wp.rcNormalPosition.right = wp.rcNormalPosition.left + nXDiff;
wp.rcNormalPosition.bottom= wp.rcNormalPosition.top + nYDiff;
::SetWindowPlacement(m_staticMovable.m_hWnd, &wp);
m_editMovable.Invalidate();
m_staticMovable.Invalidate();
}
As soon as the mouse left button down event occurs on the edit control, set the moving status, m_bMoving
, to true
.
void CMovableTrialDlg::OnMovableStaticLButtonDown(MSG* pMsg)
{
m_bMoving = true;
}
Similarly when the mouse left button is up, change the status for moving, m_bMoving
, to false
.
void CMovableTrialDlg::OnMovableStaticLButtonUp(MSG* pMsg)
{
m_bMoving = false;
}
History
I'd supply the code so that the group of controls look like a child container with a non-MDI frame/dialog and can be moved using the caption/title bar. The caption/title bar will be simulated.