MFC Getting Dialog Area - mfc

I created a common dialog class(CCommonDlg) inherited from CDialogEx.
Now I am inheriting CMyDialog from CCommonDialog. Passed CMyDialog dialog resource ID to base class CCommonDialog.I am trying to draw a circle on the dialog. So in CMyDialog::OnPaint() I tried the below code:
CPaintDC dc(this);
CRect rect;
GetWindowRect(&rect);
ScreenToClient(rect);
dc.Ellipse(rect);
While running i am seeing a part of the bigger circle. Its not fitting to the dialog. So i believe GetWindowRect is not giving me proper dialog dimension.
Can anyone please help on this.
NOTE: CommonDlg is one DLL and CMyDlg is anther dll.
Thanks

Use this code.
CPaintDC dc(this);
CRect rect;
GetClientRect(&rect); //to get client area only
dc.Ellipse(rect);
the function you are using, GetWindowRect(&rect);
It will include title bar of your window also, so in that area your Ellipse will be clipped. So as you need to draw on client area only, you should use GetClientRect(&rect);

Related

MFC Draw Stuff Outside OnPaint in a Dialog-based App

I'm currently trying to draw something outside OnPaint function. I know there are many duplicate questions on the internet, however, I failed to get any of them to work. This is entirely because of my lack of understanding of MFC.
What works inside OnPaint:
CDC* pDC = GetDC();
HDC hDC = pDC->GetSafeHdc();
CRect lDisplayRect;
GetDlgItem(IDC_DISPLAYPOS)->GetClientRect(&lDisplayRect);
GetDlgItem(IDC_DISPLAYPOS)->ClientToScreen(&lDisplayRect);
ScreenToClient(&lDisplayRect);
pDC->FillSolidRect(&lDisplayRect, GetSysColor(COLOR_3DDKSHADOW));
pDC->TextOutW(300, 300, TEXT("test"));
It fills the area of the button control I have with a defined colour.
And it prints out the "test" string without any issue.
But it won't work outside OnPaint.
I've seen numerous suggestions such as using CmemDC,CPaintDC, etc
But none of them worked outside OnPaint.
For example,
CClientDC dc(this);
dc.rectangle( ....);
does not work.
Please note that this is a temporary test code and what I am eventually trying to do is draw incoming frames from a frame grabber within my display thread (a separate thread from the main UI thread) on the DisplayPos area and my dlg object(the dialog) owns an instance of the DisplayThread class. And I'm passing HWND and displayrect upon creating the member mDisplayThread so I can draw stuff within the display thread and that's the reason why I need to be able to draw to DC outside OnPaint (DisplayThread class does not have OnPaint or inherit any class that has it).
I'm in dire need of help...Please help!
Added: I have overridden PreTranslateMessage(MSG* pMsg) and made it return without calling the default function just in case WM_ERASE msg is erasing everything, but this approach didn't work either.
For example:
void CMFCApplicationDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
HDC hdc = ::GetDC(m_hWnd);
Ellipse(hdc, point.x - 10, point.y - 10, point.x + 10, point.y + 10);
::ReleaseDC(m_hWnd, hdc);
CDialogEx::OnLButtonDown(nFlags, point);
}
Two important suggestions:
Do not draw outside of OnPaint. The content may be erased or painted over at the direction of OS.
Do not draw on the dialog surface. First, it is not designed for that. It may be affected by other controls or by theming, skinning, etc. Just create a window with your own window procedure, so you are in control.
I would store the information needed for drawing in you frame grabber, and cause an immediate window painting by calling RedrawWindow

Rectangle not showing on OnPaint MFC

I have a dialog based application written in c++ and MFC. The dialog has a CStatic picture control. I am drawing a BITMAP in the OnPaint() function of the PictureCtrl. The relevant code is as follows:
void PictureCtrl::OnPaint()
{
CDC* pDC = this->GetDC();
pDC->SelectStockObject(PS_SOLID);
pDC->Rectangle(CRect(0, 0, 400, 400));
ReleaseDC(pDC);
CStatic::OnPaint();
}
When the application runs, the rectangle is drawn right on the top-left corner of the dialog, and not the picture control.
Secondly, if I minimize and maximize the dialog window, the image shows up, but the rectangle doesn't.
However, if I hover the mouse in the windows taskbar and a tooltip appears on the icon of the dialog application, the rectangle shows up.
I want to show the rectangle over the image no matter what the user does to the window (minimize, maximize, move, etc.).
CStatic::OnPaint handles BeginPaint/EndPaint (main WinAPI functions) in response to WM_PAINT message. Therefore it should be called first. Moreover, you can use CClientDC which has automatic clean up:
void PictureCtrl::OnPaint()
{
CStatic::OnPaint();
CClientDC dc(this); //<- uses GetDC
dc.SelectStockObject(BLACK_PEN);
dc.Rectangle(CRect(0, 0, 400, 400));
} //<- ReleaseDC is automatically called
Better yet, use CPaintDC directly in response to WM_PAINT message:
void PictureCtrl::OnPaint()
{
CPaintDC dc(this); //<- calls `BeginPaint`
dc.SelectStockObject(BLACK_PEN);
dc.Rectangle(CRect(0, 0, 400, 400));
} //<- EndPaint is automatically called
Unrelated, use BLACK_PEN as parameter for SelectStockObject. Use PS_SOLID as parameter for CPen:
CPen pen(PS_SOLID, 1, RGB(0,0,0));

How can I paint a rectangle around a window without overriding the title bar in win32

I want to draw a rectangle around my window but I don't want to override the title bar.
what I wrote so far in the window callback function is:
case WM_NCPAINT:
{
HDC hdc;
RECT rect;
HPEN pen;
hdc=GetDCEx(hWnd,(HRGN)wParam,DCX_WINDOW|DCX_CACHE|DCX_INTERSECTRGN|DCX_LOCKWINDOWUPDATE);
GetWindowRect(hWnd,&rect);
pen=CreatePen(PS_SOLID, 10, RGB(255, 0, 0));//red pen 10 pixels in size
SelectObject(hdc,pen);
Rectangle(hdc,0,0,(rect.right-rect.left),(rect.bottom-rect.top));
DeleteObject(pen);
ReleaseDC(hWnd,hdc);
}
break;
However, this draws over the window title bar with white brush.
How can I make it not to paint over the title bar? I'm loosing the title bar text and the menu...
I have tried using HOLLOW_BRUSH before creating the pen as follows:
HBRUSH b=CreateSolidBrush(HOLLOW_BRUSH);
SelectObject(hdc,b);
But that only caused the title bar to not be drawn at all (being black).
By handling the WM_NCPAINT message, you are telling the window manager that you are taking responsibility for painting the entire non-client area, and so the window manager will not draw any of it for you.
If you want the original title bar to be drawn then you need to call DefWindowProc() first, then do your own drawing "on top" of what it draws.
You may also need to use ExcludeClipRect() to prevent the client area from being drawn over if you wish to draw the entire non-client area at once with a single rectangle.

CPaintDC(this) in CStatic derived class paints outside of control

As the title says.
Even with CPaintDC in the derived class the GDI drawing is not cut off.
Thanks in advance.
void CGraph::OnPaint ()
{
CPaintDC dc(this);
dc.SetViewportOrg (0, 400);
dc.SetMapMode(MM_ISOTROPIC);
dc.SetWindowExt(1000, 800);
dc.SetViewportExt(1000, -800);
// MessageBox(L"OnPaint");
ProcessData ();
DrawCoordinateSystem (&dc);
DrawGrid (&dc);
DrawGraph (&dc);
}
So, your CGraph is derived from CStatic, and the drawing code you show draws outside of the CStatic control, onto the dialog it is on? That's impossible, a control can only draw on itself. Are you sure the control isn't bigger than you think it is, and what you think is off-control actually isn't? Use spy++ to select your cstatic, it'll show you the border of the window.
Maybe what you are seeing is improper invalidation. Try dragging another window over your control, see what that does.
Otherwise, the methods to restrict the drawing area are
You manually track where to draw. Tedious.
Use SetClipRgn() to set the area to which to restrict drawing.
Not quite the same, but symptoms sometimes look similar: check the WS_CLIPSIBLINGS and WS_CLIPCHILDREN flags of your control and the dialog it's on.
Here is the way I solved the problem
CDC* pDC = GetDC();
CRect rClient(0,0,1000,800);
//GetClientRect(rClient);
CRgn ClipRgn;
if (ClipRgn.CreateRectRgnIndirect(&rClient))
{
pDC->SelectClipRgn(&ClipRgn);
}
pDC->SelectObject (PenBlack);
pDC->MoveTo (-leftMargin*zoomWidth, setPointsCorrected);
pDC->LineTo (1000*zoomWidth, setPointsCorrected);
pDC->SelectClipRgn(NULL);
ReleaseDC(pDC);

Does overriding OnNcPaint() affect the painting of the client area of a window?

I want to change the appearance of a window's caption bar, so I decided to override the OnNcPaint() method of CMainFrame. But when I did this, I found a problem. If there is another window covering my window, and I drag the window quickly, the content of the client area of my window disappeared, which came to sight only when I stopped the dragging.
My overridden OnNcPaint() is like below:
void CMainFrame::OnNcPaint()
{
CDC* pWinDC = GetWindowDC();
//do some drawing
ReleaseDC(pWinDC);
}
Is there something wrong with my approach?
Thank you!
Unless you use a clipping region set up to exclude the client area, you can paint over it from OnNcPaint(). So... if your drawing logic can't be modified to exclude the client in some other way, set up an appropriate clipping region first:
CRect rect;
GetWindowRect(&rect);
ScreenToClient(&rect);
CRect rectClient;
GetClientRect(&rectClient);
rectClient.OffsetRect(-rect.left, -rect.top);
rect.OffsetRect(-rect.left, -rect.top);
pWinDC->ExcludeClipRect(&rectClient);
// ...
// draw stuff here
// ...
pWinDC->SelectClipRgn(NULL);