I made a picture control (ID= IDC_PICTURE) to display raw data using StretchDIBits().
HWND hDlg,hWndCtl;
hWndCtl =::GetDlgItem(hDlg,IDC_PICTURE);
hdc =:: GetDC(hWndCtl);
::StretchDIBits(hdc,0,0,width,height,0,0,width,height,raw_image,m_pBitMapInfo,DIB_RGB_COLORS,SRCCOPY);
But images is displayed on my desktop screen not inside picture control I made. How can I solve this problem? Thank you very much.
In the following line ...
hWndCtl =::GetDlgItem(hDlg,IDC_PICTURE);
... you haven't initialised hDlg, so it is probably failing and hWndCtl is being returned as NULL.
Then this line ...
hdc =:: GetDC(hWndCtl);
... is effectively GetDC(NULL) which gives you the DC of the desktop.
So, to fix the problem, make sure you pass the HWND of your dialog to GetDlgItem or, as you are using MFC, use the CWnd version of GetDlgItem from within your CDialog derived class like this:
CWnd *pWnd = GetDlgItem(IDC_PICTURE); // add error checking here for NULL return
HDC hdc =::GetDC(pWnd->GetSafeHwnd()); // use the HWND of the control to get the DC
// ... do the blit ...
Related
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
can you tell me how to make a picture fit in a static control, i mean like if you create a static control for viewing pictures and if the picture quality or size of picture is bigger than control then it re size the static control with the size of picture. i could create the control and set the picture to it alright. but i don't know how to make it fit on control. this is how i create control and set picture to it.
Code:
HWND static_con(HWND hWnd, HINSTANCE hInst){
HWND Static_Pic;
Profile_Pic = CreateWindow("STATIC", NULL, SS_BITMAP|WS_CHILD|WS_VISIBLE|WS_TABSTOP, 5,5,33,33, hWnd, NULL, hInst, NULL);
HBITMAP hBmp = (HBITMAP)LoadImage(NULL, "camera1.jpg", IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
if(hBmp == NULL){
MessageBox(NULL, "Error while loading image", "Error", MB_OK|MB_ICONERROR);
}
SendMessage(Static_Pic, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBmp);
return 0;
}
and then i call the function in WM_CREATE handler which creates it successfully and now i don't know how to make it fit on control, i really appreciate if you could tell me how to make the picture fit on control.
You can use SS_REALSIZECONTROL
From Microsoft's documentation.
SS_REALSIZECONTROL - Adjusts the bitmap to fit the size of the static control.
You can also manually scale the image. Get the size of the control where image is to go by using GetWindowRect(), then by using StretchBlt() scale the image so that its dimensions match that of the source, then do STM_SETIMAGE.
I am creating a basic GUI with the Windows API and I have run into an issue. It starts with a main window that opens with a custom background color I set (RGB(230,230,230)). It then displays text in the upper left corner with the static control.
settingstext = CreateWindow("STATIC",
"SETTINGS",
SS_LEFT | WS_CHILD,
12,
20,
100,
20,
hwnd,
NULL,
proginstance,
NULL);
ShowWindow(settingstext, 1);
This works, but when the text is displayed I need a way to change the background of it to match the main window or else it just looks like it doesn't blend in.
My question is, how do I do this? I currently use the method below and it works, but I wanted to know, is there a way to permanently set the background color somehow, right after the CreateWindow function for the static control without changing system colors, and just have it apply to that one control and not anything that sends the WM_CTLCOLORSTATIC message. I have experimented around with using the GetDC function and SetBkColor function outside of the message loop but nothing works.
case WM_CTLCOLORSTATIC:
{
HDC hdcStatic = (HDC) wParam;
SetTextColor(hdcStatic, RGB(0,0,0));
SetBkColor(hdcStatic, RGB(230,230,230));
return (INT_PTR)CreateSolidBrush(RGB(230,230,230));
}
I want to do this because...
I don't want to fill up my message loop with functions that need to be called every time the window repaints.
Have the changes apply to only this static control.
I would be very thankful for any help that could be provided, at least pointing me in the right direction, thanks.
For static text controls there's no permanent way to set the text color or their background. Even if you want to apply the changes to a single static control; you would still have to handle WM_CTLCOLORSTATIC notification message in parent dlgproc just when the control is about to be drawn.
This is due to the DefWindowProc overwriting your changes to the device context each time it handles WM_CTLCOLORSTATIC as stated in the MSDN:
By default, the DefWindowProc function selects the default system colors for the static control.
static HBRUSH hBrush = CreateSolidBrush(RGB(230,230,230));
case WM_CTLCOLORSTATIC:
{
if (settingstext == (HWND)lParam)
//OR if the handle is unavailable to you, get ctrl ID
DWORD CtrlID = GetDlgCtrlID((HWND)lParam); //Window Control ID
if (CtrlID == IDC_STATIC1) //If desired control
{
HDC hdcStatic = (HDC) wParam;
SetTextColor(hdcStatic, RGB(0,0,0));
SetBkColor(hdcStatic, RGB(230,230,230));
return (INT_PTR)hBrush;
}
}
If you're looking to make the control's background transparent over a parent dialog you could use SetBkMode(hdcStatic, TRANSPARENT).
I think there is a permanent way to do it.
Just after you create the label,use GetDC() function to get the Device Context.
Then use:
SetTextColor(hdcStatic, RGB(0,0,0));
SetBkColor(hdcStatic, RGB(230,230,230)); // Code Copied from the above answer by cpx.
And it should do .
Have you considered subclassing the static window and doing owner draw?
I'm trying to get thumbnail pictures of windows that are not visible.
Here's the code I have so far
BOOL CALLBACK WindowProc(HWND hWnd, LPARAM lParam)
{
RECT WindRect;
GetWindowRect(hWnd, &WindRect)
CurrentScreenShot->Next = new ScreenShotList();
CurrentScreenShot = CurrentScreenShot->Next;
HDC SourceDC = GetDC(hWnd);
HDC TargetDC = CreateCompatibleDC(SourceDC);
CurrentScreenShot->ScreenShot = CreateCompatibleBitmap(SourceDC, WindRect.right - WindRect.left, WindRect.bottom - WindRect.top);
BitBlt(TargetDC, 0, 0, WindRect.right - WindRect.left, WindRect.bottom - WindRect.top, SourceDC, 0, 0, SRCCOPY);
ReleaseDC(hWnd, SourceDC);
g_iWindows++;
return TRUE;
}
For now, WindowProc is being called directly using FindWindow to get a handle, though, I eventually want to use EnumWindows to loop through all of the windows to get their thumbnails and store them in a linked list.
WindowProc(FindWindow(NULL, L"File Explorer"), 0);
This code is in a DLL, which is called from a C# Forms application. For now the C# application just takes the bitmap and saves it to a file.
The problem is that unless I use FindWindow to get the visible window (which also happens to be the C# application), the picture ends up being a black box.
Is it possible to get an picture of a background window?
EDIT: This is a Windows Mobile application
There is no redrawing going on for invisible Windows, thats why you cannot get their content from the DC. Try sending a WM_PRINT message to the target window to request that it draws its content to your DC.
Edit:
Sorry, i did not notice this was for Windows Mobile. Other than WM_PRINT, i don't know a way to get the content of an invisible window. Of course you can still show the window (and make sure it is on top / not covered by other windows) and then run the code you have, but thats probably a bit messy.
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.