I tried to get an HDC from QPushButton to use with DrawIconEx():
HWND hw=(HWND)(ui->watch_1->winId());
HDC hdc=GetDC(hw);
DrawIconEx(hdc,00,0,LoadIcon(NULL, MAKEINTRESOURCE(32513)),0, 0, 0, NULL, DI_NORMAL);
(watch_1 is a QPushButton)
But it is not working. How can I get the HDC?
I can't even get an HDC from QWidget, either.
Related
In C++ code, I need to take a screenshot of a given window, store the pixels in memory, and then load them into an SFML Image object. So far, I have a handle to the window I need to screenshot and can create an HBITMAP object of it:
HWND window = FindWindow(TEXT("WindowName"), NULL);
RECT rc;
GetClientRect(window , &rc);
HBITMAP hbmp;
HDC hdcScreen = GetDC(NULL);
HDC hdc = CreateCompatibleDC(hdcScreen);
hbmp = CreateCompatibleBitmap(hdcScreen,
rc.right - rc.left, rc.bottom - rc.top);
SelectObject(hdc, hbmp);
PrintWindow(window, hdc, PW_CLIENTONLY);
GetObject(hbmp, sizeof(BITMAP), bitmap);
Now to be honest, I'm not really much of a Windows guy and I don't understand what's really happening with this WinAPI stuff here, this is just some code I found online to get screenshots. What I need to do is get this into some type of standard format that I can pass into SFML's function:
sf::Image::loadFromMemory(const void * data, std::size_t size)
And preferably something that will also be easy to send over a socket connection later. How can I get a nice, non-Windows-specific format for my screenshot?
It seems the flickering is generated by the CombineRgn function, but I really have no idea why this happens, since i've never used regions that much I'm possibly missing some knowledge on the matter.
Some events in the program triggers the addition of little rectangles to the main region, here's the code that handles that:
HRGN ActualRegion = CreateRectRgn(0, 0, 0, 0);
GetWindowRgn(hwnd, ActualRegion);
HRGN AddedRect = CreateRectRgn(//long code that creates a rectangle)
CombineRgn(ActualRegion, ActualRegion, AddedRect, RGN_OR);
SetWindowRgn(hwnd, ActualRegion, FALSE);
InvalidateRect(hwnd, NULL, FALSE);
White Flickering appears only after the invalidation if new regions where combined to the main one.
Here's how I'm implementing double buffering in WM_PAINT:
PLEASE NOTE that on creation i'm enabling the DWM blur behind function with an invalid region (different from the Main one) which means that everything painted with BLACK_BRUSH will result in a 100% "invisible" portion of the program
RECT r; GetClientRect(hwnd, &r);
PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps);
HDC MemDc = CreateCompatibleDC(hdc);
HBITMAP hBmp = CreateCompatibleBitmap(hdc, r.right, r.bottom);
HBITMAP hOld = (HBITMAP)SelectObject(MemDc, hBmp);
//Making sure this dc is filled with "invisible" pixels to display
SelectObject(MemDc, GetStockObject(BLACK_BRUSH));
Rectangle(MemDc, //arbitrary values that matches the entire screen);
BitBlt(hdc, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), MemDc, 0, 0, SRCCOPY);
//clean-up
SelectObject(MemDc, hOld);
DeleteObject(hBmp);
DeleteDC(MemDc);
EndPaint(hwnd, &ps);
WM_ERASEBKGND obviously returns TRUE without further handling, the WNDCLASSEX instance of the window has a default BLACK_BRUSH as the hbrBackground field.
I also tried to intercept and return TRUE from WM_NCPAINT message.
I'm doing everything necessary to avoid intermediate drawcalls, everything handled inside the WM_PAINT uses a backbuffer, also i'd like to mention i'm not working with images/bitmaps. Everything is drawn with gdi/gdi+, and in no place i'm actually issuing a "white" redraw that may possibly cause said flicker. I'm a bit lost here
Is it something that i'm possibly missing ? I can't really understand what may be causing white flickering in this scenario
The problem is not the CombineRgn function but the SetWindowRgn function which you call before the system draws the window for the first time. If you call SetWindowRgn after the first draw, no flicker. Unfortunatelly I don't know why. So, a way to counter that is to set the window region after the first draw (take the code that sets window region from WM_CREATE and leave only the DwmEnableBlurBehindWindow):
static int stc = 0;
//in WM_PAINT after the EndPaint(hwnd, &ps); add
HRESULT lr = DefWindowProc(hwnd, message, wParam, lParam);
if( stc == 0 ){
OnlyOnce();
stc++;
}
return lr;
and the OnlyOnce:
void OnlyOnce(void){
int X_Screen = GetSystemMetrics(SM_CXSCREEN);
int Y_Screen = GetSystemMetrics(SM_CYSCREEN);
HRGN ActualRegion = CreateRectRgn(X_Screen - 100, Y_Screen - 100, X_Screen - 100 + 40, Y_Screen - 100 + 40);
SetWindowRgn(hWnd, ActualRegion, true);
return;
}
The bitmap will not display when the left mouse button is clicked.
I'm using visual c++ express
HDC DC, memDC;
switch(message) {
case WM_CREATE:
hBit1 = LoadBitmap(hInst, "C:\New folder (2)\MyBP1.bmp");
break;
case WM_LBUTTONDOWN:
DC = GetDC(hwnd);
memDC = CreateCompatibleDC(DC);
SelectObject (memDC, hBit1);
BitBlt(DC, LOWORD(lParam), HIWORD(lParam), 27, 59, memDC, 0, 0, SRCCOPY);
ReleaseDC(hwnd, DC);
DeleteDC(memDC);
break;
I'm not sure exactly whats wrong with the code.
Theres no errors displayed in visual c++ express
If the code is all wrong would someone point me in the right direction
LoadBitmap is only for loading bitmaps that are stored as resources in your executable or a DLL.
To load a bitmap from a BMP file, you want to use LoadImage with the LR_LOADFROMFILE flag, something like this:
bmp = (HBITMAP)LoadImage(0, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
As an aside, you probably don't really want to do the displaying directly in response to WM_LBUTTONDOWN. Instead, you normally want to record the position, possibly set a flag to indicate that the bitmap should be displayed, and call InvalidateRect to invalidate your client rectangle -- then do the actual drawing in response to WM_PAINT.
I'm using win32 for 2D animation. My program so far loads an array of HBITMAP objects created from resource. The problem arises during animation when calling CreateCompatibleDC() from "OnUpdate()" in code below. AFTER MANY CALLS to the OnUpdate function, the HDC object is not created(possibly not allocated in memory). This causes unexpected results when DeleteDC() is called to delete the HDC object. Here is the update function code from main.cpp:
void OnUpdate(
HWND hwnd)
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd,&ps);
if(!hdc)
{
MessageBox(NULL, L"Failed to Create Compatible DC - 'hdc' in OnUpdate()", L"ALERT", MB_OK);
PostMessage(hwnd, WM_DESTROY, NULL, NULL);
}
HPALETTE hpalT = SelectPalette(hdc,hpal,FALSE);
BITMAP bm;
HDC hdcMem = CreateCompatibleDC(hdc);
if(!hdcMem)
{
MessageBox(NULL, L"Failed to CreateCompatibleDC - 'hdcMem' in OnUpdate()", L"ALERT", MB_OK);
PostMessage(hwnd, WM_DESTROY, NULL, NULL);
}
SelectBitmap(hdcMem, bkgMain);
GetObject(bkgMain, sizeof(bm), &bm);
BitBlt(backDC, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);
// Clean up.
if(!DeleteDC(hdcMem))
{
MessageBox(NULL, L"Failed to DeleteDC - 'hdcMem' in OnUpdate()", L"ALERT", MB_OK);
PostMessage(hwnd, WM_DESTROY, NULL, NULL);
}
SelectPalette(hdc,hpalT,FALSE);
EndPaint(hwnd,&ps);
}
What is SelectBitmap()?
If it's a wrapper/alias for SelectObject() then you're leaking a bitmap.
SelectBitmap(hdcMem, bkgMain);
You should select the old bitmap back into the DC before deleting it:
This function returns the previously selected object of the specified
type. An application should always replace a new object with the
original, default object after it has finished drawing with the new
object.
I had a similar problem and found it was caused by calling CreateCompatibleDC from WM_CREATE (before my main window was created). I found GetDC(hwnd) gave me a HDC for the main window, but it could not be used until WM_CREATE was finished. I relocated my code to WM_PAINT and my code worked well.
I have this STATIC control displayed over a window that has an image as its background. When I initiate the control it displays a text. If I want to change the text inside a WM_TIMER message it is displayed over the initial text (it is not removed) I have tried UpdateWindow and InvalidateRect but id doesn't work.
This is my code
WM_CREATE:
HWND control = CreateWindowEx(
WS_EX_TRANSPARENT,
L"STATIC",
L"FirstText",
WS_CHILD|WS_VISIBLE|ES_LEFT,
0,
0,
200,
20,
hWnd,
HMENU(LABEL1),
Instance,
NULL
);
break;
case WM_TIMER:
SetWindowText(GetDlgItem(hWnd, LABEL1), L"SecondText");
KillTimer(hWnd, MYTIMER);
// Here I tried UpdateWindow and InvalidateRect but no result
break;
So, the second text is drawn over the first one. It looks like the STATIC content is not updated after changing it. What could be going wrong? Thanks!
I hard coded some numbers in there for testing (like the window ID) - but it's just an example to show you.
case WM_CREATE:
control = CreateWindowEx(
WS_EX_TRANSPARENT,
L"STATIC",
L"FirstText",
WS_CHILD|WS_VISIBLE|ES_LEFT,
0,
0,
200,
20,
hWnd,
HMENU(99),
hInst,
NULL
);
//Create a timer
SetTimer(hWnd,23, 5000,NULL);
break;
case WM_CTLCOLORSTATIC:
if ( GetDlgItem(hWnd, 99) == (HWND)lParam)
{
SetBkMode( (HDC)wParam, TRANSPARENT);
return (LRESULT) GetStockObject(HOLLOW_BRUSH);
}
break;
case WM_TIMER:
{
SetWindowText(GetDlgItem(hWnd, 99), L"Second Text");
KillTimer(hWnd, 23);
RECT rect = {0,0, 200,20};
InvalidateRect(hWnd, &rect, TRUE);
UpdateWindow(hWnd);
}
break;
case WM_PAINT:
{
hdc = BeginPaint(hWnd, &ps);
//Load my test bitmap from resources
HBITMAP hb = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BITMAP1));
BITMAP bm;
GetObject(hb, sizeof(BITMAP), &bm);
HDC memDC= CreateCompatibleDC(hdc);
SelectObject(memDC,hb);
// ========================
//Put the bitmap on the main window to act as a backdrop
BitBlt(hdc, 0,0, bm.bmWidth,bm.bmHeight,memDC,0,0, SRCCOPY);
DeleteDC(memDC);
EndPaint(hWnd, &ps);
}
break;