Rectangle not showing on OnPaint MFC - c++

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));

Related

ATL project pushbutton color change

We have a requirement to change the color of pushbutton/control. I have controls defined in resource file.
We have tried multiple ways
1)Using CMFCButton Object I got defination ambiguity errors
2)
Using CBUtton CDC* pdcWindow1 = m_Button.GetWindowDC(); CRect rect1; GetClientRect(&rect1); pdcWindow1->FillSolidRect(&rect1, (RGB(0, 0, 255)));
No effect on Button color no error as well.
Inputs which i have got so far : we have used ATLcontrols and to color Button we need MFC Functions, here ATL and MFC libs can't coexist they are causing ambiguity errors as both have same functional definitions.
Is it even possible to color ATL controls without MFC functions.?
only solution is --https://jeffpar.github.io/kbarchive/kb/173/Q173974/??
Look of standard Windows GDI buttons is customized according to Button Color Messages:
The system sends a WM_CTLCOLORBTN message to a button's parent window before drawing a button. This message contains a handle to the button's device context and a handle to the child window. The parent window can use these handles to change the button's text and background colors. However, only owner-drawn buttons respond to the parent window processing the message.
In ATL project, you would either handle this notification message in parent window class or use more sophisticated message forwarding (reflection) to reflect this message to button class.
Either way you don't really paint (FillSolidRect), you can just update colors in the message handler. And also pay attention that only owner-drawn buttons expose this functionality.
See also: Owner-drawn button, WM_CTLCOLORBTN and WM_DRAWITEM (clearing an HDC)
This is how I was able to achieve :
HINSTANCE hInstance = GetModuleHandle(NULL);
HANDLE hBitmap = LoadImage(hInstance, MAKEINTRESOURCE(IDB_CURCANCEL_LOGO), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
HANDLE hBitmap1 = LoadImage(hInstance, MAKEINTRESOURCE(IDB_CURLOGIN_LOGO), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
const HWND hOriginalLoginButton = GetDlgItem(IDOK);
const HWND hOriginalCancelButton = GetDlgItem(IDCANCEL);
SendMessage(hOriginalLoginButton, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap1);
SendMessage(hOriginalCancelButton, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap);
Now i am trying to make corners rounded.

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

MFC Getting Dialog Area

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);

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.

How to draw in the nonclient area?

I'd like to be able to do some drawing to the right of the menu bar, in the nonclient area of a window.
Is this possible, using C++ / MFC?
Charlie hit on the answer with WM_NCPAINT. If you're using MFC, the code would look something like this:
// in the message map
ON_WM_NCPAINT()
// ...
void CMainFrame::OnNcPaint()
{
// still want the menu to be drawn, so trigger default handler first
Default();
// get menu bar bounds
MENUBARINFO menuInfo = {sizeof(MENUBARINFO)};
if ( GetMenuBarInfo(OBJID_MENU, 0, &menuInfo) )
{
CRect windowBounds;
GetWindowRect(&windowBounds);
CRect menuBounds(menuInfo.rcBar);
menuBounds.OffsetRect(-windowBounds.TopLeft());
// horrible, horrible icon-drawing code. Don't use this. Seriously.
CWindowDC dc(this);
HICON appIcon = (HICON)::LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
::DrawIconEx(dc, menuBounds.right-18, menuBounds.top+2, appIcon, 0,0, 0, NULL, DI_NORMAL);
::DestroyIcon(appIcon);
}
}
In order to draw in the non-client area, you need to get the "window" DC (rather than "client" DC), and draw in the "window" DC.
You should try handling WM_NCPAINT. This is similar to a normal WM_PAINT message, but deals with the entire window, rather than just the client area. The MSDN documents on WM_NCPAINT provide the following sample code:
case WM_NCPAINT:
{
HDC hdc;
hdc = GetDCEx(hwnd, (HRGN)wParam, DCX_WINDOW|DCX_INTERSECTRGN);
// Paint into this DC
ReleaseDC(hwnd, hdc);
}
This code is intended to be used in the message loop of your applicaton, which is canonically organized using a large 'switch' statement.
As noted in the MFC example from Shog, make sure to call the default version, which in this example would mean a call to DefWindowProc.
If you just want something in the menu bar, maybe it is easier/cleaner to add it as a right-aligned menu item. This way it'll also work with different Windows themes, etc.