I'm developing an MFC application that displays real-time LiDAR point clouds, on Visual Studio 2017 in a windows environment.
Now all the display functionalities are working just fine, and I've implemented them as follows:
Added a static picture element to my CDialog
dialog using the resources editor, called it IDC_PICTURE
.
Defined the following in the header file of my class :
CStatic m_Picture;
CRect m_rectangle;
Linked the static picture (IDC_PICTURE
) with the CStatic attribute (m_picture
) as follows:
void MyDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_PICTURE, m_Picture);
//other static lists and indicators
}
Get the picture dimensions and coordinates by associating a CRect
element to it, I've done this as follows:
In my OnInitDialog()
, I've associated m_picture to m_rectangle
, then got the dimensions in separate variables as follows:
m_Picture.GetWindowRect(m_rectangle);
PicWidth = m_rectangle.Width();
PicHeight = m_rectangle.Height();
Then, to display the point clouds, I've written a function called DrawData
that has the following body:
int MyDlg::DrawData(void)
{
CDC* pDC = m_Picture.GetDC();
CDC memDC;
CBitmap bmp;
bmp.CreateCompatibleBitmap(pDC, PicWidth, PicHeight);
//iterate over the points in my point cloud vector
// use memDC.setpixel() method to display the points one by one
//then:
pDC->StretchBlt(0, 0, PicWidth, PicHeight, &memDC, 0, 0, PicWidth, PicHeight, SRCCOPY);
bmp.DeleteObject();
memDC.DeleteDC();
ReleaseDC(pDC);
}
Until here all is good. My problem is in what follows.
Now I need to show the coordinates of the mouse cursor only inside the rectangle (the IDC_PICTURE) and according to the rectangle's coordinate system (not the whole window).
So, I've integrated OnMouseMove()
function in my code by doing the following:
BEGIN_MESSAGE_MAP(CalibrationDLG, CDialog)
ON_WM_PAINT()
ON_WM_MOUSEMOVE() // added this to take mouse movements into account
//OTHER BUTTON MESSAGES..
END_MESSAGE_MAP()
The body of the function looks like this:
void CalibrationDLG::OnMouseMove(UINT nFlags, CPoint point)
{
CDC* dc;
dc = GetDC();
CString str;
CPoint ptUpLeft = m_rect_calib.TopLeft(); // get the coordinates of the top left edge of the rectangle
CPoint ptDownRight = m_rect_calib.BottomRight(); // get the coordinates of the bottom right edge of the rectangle
if (point.x >= ptUpLeft.x && point.x <= ptUpLeft.x+ m_rect_calib.Width() && point.y >= ptUpLeft.y && point.y <= ptUpLeft.y+ m_rect_calib.Height())
{
str.Format(_T("x: %d y: %d"), point.x, point.y);
dc->TextOut(10, 10, str);
ReleaseDC(dc);
CDialog::OnMouseMove(nFlags, point);
}
}
My problem is that the coordinates I'm getting are not correct. Even the limits of the area defined in my condition:
if (point.x >= ptUpLeft.x &&
point.x <= ptUpLeft.x + m_rect_calib.Width() &&
point.y >= ptUpLeft.y &&
point.y <= ptUpLeft.y + m_rect_calib.Height())
don't seem to limit the area I'm looking for. It is way smaller than the real IDC_PICTURE
surface.
Does anyone know what I'm missing here? How do I transform the mouse coordinates to make them only relative to the IDC_PICTURE area? Thanks
The coordinates are relative to the client area of whatever handles the mouse move event, in your case the dialog. You want them relative to the picture control's client area. You can transform between them by recognizing they have common screen coordinates.
// transform from this dialog's coordinates to screen coordinates
this->ClientToScreen(&point);
// transform from screen coordinates to picture control coordinates
m_picture.ScreenToClient(&point);
You could do away with all this transforming if instead of handling the mouse move of the whole dialog, you derive your own picture class from CStatic
and handle it's OnMouseMove
. Then the point you receive will already be in the picture control's coordinates.