Why is my mouse cursor coordinates suddenly scaled? - c++

At the beginning, sorry about my English.
I'm now learning how to build a MFC application in visual studio 2015. I'm using Direct2D to draw lines in a window.
When left button is down, my OnLbuttonDown() function is called:
void CMyProjectNameView::OnLButtonDown(UINT nFlags, CPoint point)
{
startPoint = point; // start point of the line, a gloable variable.
pRenderTarget->BeginDraw();
CView::OnLButtonDown(nFlags, point);
}
When left button is up, my OnLButtonUp() function is called:
void CMyProjectNameView::OnLButtonUp(UINT nFlags, CPoint point)
{
pRenderTarget->DrawLine(startPoint, point, m_pbrush, 1.0f); // draw the line
pRenderTarget->EndDraw();
CView::OnLButtonUp(nFlags, point);
}
So it will draw a line in the window when I drag my mouse, and it works fine yesterday.
The problem is when I run it today, it suddenly become abnormal. The start point coordinates and end point coordinates is two times bigger than before. So When I draw the line, the line shows on the bottom right position compared to the position it supposed to be.
For instance, if I draw a line from (100,100) to (500,500), a line start from (100,100) to (500,500) will appear on screen, but when I click left button of my mouse at (100,100), move it to (500,500) and release left button, a line from (200,200) to (1000,1000) will be drawn.
OnLButtonDown(UINT nFlags, CPoint point)
OnLButtonUp(UINT nFlags, CPoint point)
So basically, these two point above is scaled before they are passed in. Do I accidentally change any configurations? Is there any way to fix this? I am sure I didn't change my code.

Coordinates for DrawLine are in device-Independent pixels. See also DPI and Device-Independent Pixels
You have probably changed the size of client rectangle, it needs to be adjusted. Try also to resize the window and see if it gets the right coordinates.
CRect rc;
GetClientRect(&rc);
D2D1_SIZE_F size = pRenderTarget->GetSize();
const float x = size.width / rc.right;
const float y = size.height / rc.bottom;
D2D1_POINT_2F p1;
D2D1_POINT_2F p2;
p1.x = 100 * x;
p1.y = 100 * y;
p2.x = 500 * x;
p2.y = 500 * y;
pRenderTarget->DrawLine(p1, p2, brush);

Related

SetPixel sets pixel below desired point C++

I have the following code:
POINT p;
int main(void) {
HDC hdc = GetDC(NULL);
while(!GetAsyncKeyState(VK_F1)) {
GetCursorPos(&p);
SetPixel(hdc, p.x, p.y, RGB(73, 214, 0));
}
DeleteObject(hdc);
}
What I want to achive is when I move mouse the pixel at curent cursor position changes its color until the program is stopped. However I see a few issues here:
The pixel is drawn below cursor position (resolution?) and after some time all pixels changes to default color. How Can I resolve the problem? Thanks for any help.

Find the control which mouse is over in MFC

Is there anyway when mouse moving find the control mouse is over on it? I mean if you have a dialog with some labels and text boxes, and the mouse move to label, notify me that label name, after that if move it to text box notify the text box name.
If you handle WM_MOUSEMOVE within your dialog, you can grab the mouse position, convert it to dialog coordinates, and determine what control lies underneath the cursor point.
After some research, I came to this code which let me know if the mouse cursor is over my control in a dialog box.
//Handling mouse move in mfc dialog
void CDialogRoll::OnMouseMove(UINT nFlags, CPoint point)
{
CRect rect1;
m_FrameArea.GetClientRect(&rect1); //control rectangle
m_FrameArea.ClientToScreen(&rect1)
ScreenToClient(&rect1); //dialog coordinates`
if (point.x >= rect1.left && point.x <= rect1.right && point.y >= rect1.top &&
point.y <= rect1.bottom) {
char str[100];
sprintf(str, "%d-%d", point.x - rect1.left, point.y - rect1.top);
}
CDialogEx::OnMouseMove(nFlags, point);
}

Client rectangle coordinates on screen

How can I get coordinates of a window's client area relative to screen?
I thought about using GetClientRect and ClientToScreen. Also, in a browser window what is ClientRect? Only rectangle with HTML document shown in it, or it includes browser bars and pop-up menus, that can possibly shrink dimension for HTML doc?
I've tried this:
HWND hWnd;
RECT rc;
if (GetClientRect(hWnd, &rc)) // get client coords
{
MapWindowPoints(hWnd, NULL, reinterpret_cast<POINT*>(&rc), 2); // converts rect rc points
return rc.top;
}
But the sad thing is that browser's client rectangle includes all those pop-up browser menus and bars, therefore can't be used to detect accurate coordinates of browsers HTML document space. If anyone got suggestions how it can be done, will try it gladly.
Yes, you can do this with the ClientToScreen function:
RECT rc;
GetClientRect(hWnd, &rc); // get client coords
ClientToScreen(hWnd, reinterpret_cast<POINT*>(&rc.left)); // convert top-left
ClientToScreen(hWnd, reinterpret_cast<POINT*>(&rc.right)); // convert bottom-right
What is the "client" rectangle in a browser depends on the browser implementation. You can use Spy++ to discover this for yourself.
To translate a window's client rectangle to screen coordinates, call the MapWindowPoints function. It implements special handling to always return a valid RECT, even when used in scenarios that involve windows with right-to-left layout:
If hWndFrom or hWndTo (or both) are mirrored windows (that is, have WS_EX_LAYOUTRTL extended style) and precisely two points are passed in lpPoints, MapWindowPoints will interpret those two points as a RECT and possibly automatically swap the left and right fields of that rectangle to ensure that left is not greater than right.
Calling ClientToScreen on both points in contrast fails to account for RTL layouts, and can produce an invalid RECT. It fails to adhere to one of the rectangle coordinate invariants:
The coordinate value of a rectangle's right side must be greater than that of its left side. Likewise, the coordinate value of the bottom must be greater than that of the top.
A reliable function to return a window's client rectangle in screen coordinates would look like this:
RECT client_rect_in_screen_space(HWND const hWnd) {
RECT rc{ 0 };
if (!::GetClientRect(hWnd, &rc)) {
auto const err_val{ ::GetLastError() };
throw std::system_error(err_val, std::system_category());
}
::SetLastError(ERROR_SUCCESS);
if(::MapWindowPoints(hWnd, nullptr, reinterpret_cast<POINT*>(&rc), 2) == 0) {
auto const err_val{ ::GetLastError() };
if (err_val != ERROR_SUCCESS) {
throw std::system_error(err_val, std::system_category());
}
}
return rc;
}
The question update asks for a different, unrelated issue. There is no API built into the system, that allows you to query a web browser's display area for its HTML content. The most promising solution would be to employ UI Automation. The question, however, is too broad to provide a more detailed answer here.
As commented by Raymond Chen, the preferred way of doing this should be something like the following:
inline POINT get_client_window_position(const HWND window_handle)
{
RECT rectangle;
GetClientRect(window_handle, static_cast<LPRECT>(&rectangle));
MapWindowPoints(window_handle, nullptr, reinterpret_cast<LPPOINT>(& rectangle), 2);
const POINT coordinates = {rectangle.left, rectangle.top};
return coordinates;
}
POINT origin;
origin.x = 0;
origin.y = 0;
ClientToScreen(hWnd, &origin);
Now origin is, in screen coords, the top left corner of the client area.
To convert (x,y) from client-area coords to screen coords, add origin.
To do the reverse, subtract.

C++ MFC button disappears at window resize

I have a Dialog in MFC C++ that has a CButton attached.
I want to modify OnSize() so that the button will anchor to bottom-left.
if (btn.m_hWnd) {
CRect winRect;
GetWindowRect(&winRect);
int width = winRect.right - winRect.left;
int height = winRect.bottom - winRect.top;
int x = width - wndWidth;
int y = height - wndHeight;
CRect rect;
btn.GetWindowRect(&rect);
rect.left += x;
rect.top += y;
btn.MoveWindow(&rect);
ScreenToClient(&rect);
btn.ShowWindow(SW_SHOW);
}
x and y are the difference of how much the window has changed and will be added to the button's start coordinates.
I am not sure about the last 2 commands (I might as well delete them) but then I run the program the button disappears.
I need to know a way to move the button by x and y.
The original code was using the wrong coordinate system for both the parent dialog, and the button.
A correct way to dock to the bottom left would be like this:
if (btn.m_hWnd) {
CRect winRect;
GetClientRect(&winRect);
CRect rect;
btn.GetWindowRect(&rect);
ScreenToClient(&rect);
int btnWidth = rect.Width();
int btnHeight = rect.Width();
rect.left = winRect.right-btnWidth;
rect.top = winRect.bottom-btnHeight;
rect.right = winRect.right;
rect.bottom = winRect.bottom;
btn.MoveWindow(&rect);
}
OR
if (btn.m_hWnd) {
CRect winRect;
GetClientRect(&winRect);
CRect rect;
btn.GetWindowRect(&rect);
ScreenToClient(&rect);
int btnWidth = rect.Width();
int btnHeight = rect.Width();
btn.SetWindowPos(NULL,winRect.right-btnWidth,winRect.bottom-btnHeight,0,0,SWP_NOSIZE|SWP_NOZORDER);
}
Basically, the answer should be to do ScreenToClient before MoveWindow!
Some more detail: You need to familiarize yourself with what function returns or uses client coordinates (and relative to what these client coordinates are) and which screen coordinates; this is one of the parts of MFC which can be really confusing. As to your question:
CWnd::GetWindowRect returns screen coordinates; CWnd::MoveWindow expects coordinates relative to the parent CWnd (or to the screen if it's a top level window). So before calling MoveWindow, you have to convert the rect returned by GetWindowRect to client coordinates of your parent window; suppose pParent is the CWnd * to the parent window of btn, then your moving code should look like this:
CRect rect;
btn.GetWindowRect(&rect);
pParent->ScreenToClient(&rect); // this line and it's position is important
rect.left += x;
rect.top += y;
btn.MoveWindow(&rect);
If you're in a method of the parent window (as I think you are, since you mention OnSize of the dialog), then just leave out the pParent->. The way you do ScreenToClient at the moment, it has no effect on MoveWindow, since it's executed after it!

Qt drawPixmap isn't drawing what I expect

I'm trying to make a Paint application in C++ with Qt. Everytime I click or click & drag the mouse, the program will draw something on a pixmap. After that, it updates the window calling paintEvent(), which will draw the pixmap onto the window.
void QPaintArea::mousePressEvent(QMouseEvent *event){
startpoint = event->pos();
drawPoint(startpoint);
is_pressed = true;
}
void QPaintArea::mouseReleaseEvent(QMouseEvent *event){
is_pressed = false;
}
void QPaintArea::mouseMoveEvent(QMouseEvent *event){
if(is_pressed == true){
endpoint = event->pos();
drawLine(startpoint, endpoint);
startpoint = endpoint;
}
else{
return;
}
}
void QPaintArea::paintEvent(QPaintEvent *event){
QDesktopWidget *desktop = QApplication::desktop();
int x = (desktop->width() - 800) / 2;
int y = (desktop->height() - 600) / 2;
QPainter painter(this);
QRect target(QPoint(x, y - 35), QSize(800, 600));
QRect dirtyrect(QPoint(0,0), QSize(800, 600));
painter.drawPixmap(target, *pixmap, dirtyrect);
}
The problem is that, the program is not printing the pixmap onto the window as expected. For example, I press the mouse at x: 17, y: 82 trying to draw something. The program will print what I drew but at an offset location, like x + 20, y.
Maybe I don't fully understand how QRect or drawPixmap works, but the pixmap is 800x600. "dirtyrect" is supposed to save the entire pixmap (starting a x: 0, y: 0, and the size 800x600).
drawPixmap(target, pixmap, source) paints on target rect of painter area (QPaintArea in this case) source part of pixmap. So you paint whole pixmap (0,0,800,600) at some (x,y-35,800,600) rect of QPaintArea. If you want to paint whole pixmap on whole QPaintArea just use drawPixmap(QPoint(0,0), *pixmap).
// EDIT
But if you expected, that pixmap will be painted with some offset from QPaintArea top left corner, then your calculations are wrong, and if you wont explain what did you want to achieve we won't be able to help you. Explain us your calculations of x,y (and magic -35 for y), and maybe we will be able to figure something out
// EDIT
You don't have to use window offsets like -35 if you're painting on widget. 0,0 of the widget is not top left corner of window frame, but of widget contents. How do you expect it to behave on other platforms?
If you want to paint it in the middle of your window simply use:
void QPaintArea::paintEvent(QPaintEvent *event){
QPoint middle = geometry.center();
int x = middle.x() - 800/2; // probably best would be pixmap->width()/2
int y = middle.y() - 600/2; // probably best would be pixmap->height()/2
QPainter painter(this);
painter.drawPixmap(QPoint(x,y), *pixmap);
}