Myslím, že název vlákna mluví za vše
Fórum › C / C++
Změna backgroundu a stylu okna za běhu aplikace ve Win32 API
![](img/forum_vlakno_help_vyreseno.png)
Styl změníš přes SetWindowLong (pro dané okno), štětec na vykreslení pozadí přes SetClassLong (pro danou třídu oken). Pokud je to okno v tvé moci, tj. reaguješ přímo na WM_ zprávy, tak pozadí změníš reakcí na WM_ERASEBKGND.
Takže když v WM_ERASEBKGND zavoláš toto:
RECT rtRect;
GetClientRect(hWnd, &rtRect);
FillRect(hDC, &rtRect, (HBRUSH)(COLOR_INFOBK + 1));
// mazeme sami
return(TRUE);
tak máš pořád hnus šedivej? :)
Jinak sem musíš šoupnout kód, bez něj se dál asi nepohneme. A bitmapu vykreslíš do HDC, stejně jako cokoliv jiného grafického.
#include "main.h"
#include <commctrl.h>
#include <tchar.h>
#include <mmsystem.h>
#define _MainClassName TEXT("WinAPIMainClass")
#define _AppName TEXT("System info")
#define _TimerClock 1
#pragma comment(lib, "user32.lib")
HINSTANCE g_hInstance;
TCHAR name [ UNLEN + 1 ];
DWORD size = UNLEN + 1;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK DialogProc(HWND, UINT, WPARAM,LPARAM);
HWND konec, text[100];
HWND g_hwndMain;
HWND g_hwndStatusBar;
HWND hlavni_okno;
int setfont (HWND hwnd)
{
HFONT hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
SendMessage(hwnd,WM_SETFONT, (WPARAM)hFont, (LPARAM)TRUE);
return 0;
}
TCHAR ch[20];
MSG msg;
BOOL DumpResource(WORD id, char *filename)
{
HRSRC rsrc;
HGLOBAL load;
LPVOID data;
DWORD size;
BOOL status = FALSE;
if ((rsrc = FindResource(NULL, MAKEINTRESOURCE(id), "BINARY")) != NULL &&
(load = LoadResource(NULL, rsrc)) != NULL &&
(data = LockResource(load)) != NULL &&
(size = SizeofResource(NULL, rsrc)) != 0)
{
FILE *file;
if ((file = fopen(filename, "wb")) != NULL) {
if (fwrite(data, 1, size, file) == size)
status = TRUE;
fclose(file);
}
}
return status;
} //DumpResource(IDR_SOUBOR1, "hudba.mp3");
LRESULT CALLBACK WindowProcMain(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
TCHAR chText[200];
SYSTEMTIME sysTime;
INT_PTR dlgResult;
switch ( message )
{
case WM_COMMAND:
switch ( LOWORD(wParam) )
{
case IDB_KONEC:
DestroyWindow(konec);
DestroyWindow(g_hwndStatusBar);
SetWindowLong(hlavni_okno, GWL_STYLE, WS_OVERLAPPEDWINDOW);
ShowWindow(hlavni_okno, SW_SHOWDEFAULT);
UpdateWindow(hlavni_okno);
SendMessage(hwnd,WM_ERASEBKGND,NULL,NULL);
break;
}
case WM_CREATE:
konec = CreateWindowEx(NULL,"BUTTON", "Konec", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON , 500,320,70,25,hwnd,(HMENU)IDB_KONEC, NULL,NULL);
setfont(text[1]);
setfont(konec);
break;
case WM_SIZE:
SendMessage(g_hwndStatusBar, WM_SIZE, wParam, lParam);
break;
case WM_TIMER:
GetLocalTime(&sysTime);
_stprintf(chText, TEXT(" Dnes je: %d.%d.%d, %d:%.2d:%.2d hod."), sysTime.wDay, sysTime.wMonth, sysTime.wYear, sysTime.wHour, sysTime.wMinute, sysTime.wSecond); SetWindowText(g_hwndStatusBar, chText);
break;
case WM_CLOSE:
if ( MessageBox(hwnd, TEXT("Opravdu ukončit?"), _AppName, MB_YESNO | MB_ICONWARNING | MB_TASKMODAL) != IDYES )
return 0;
KillTimer(hwnd, _TimerClock);
break;
case WM_ERASEBKGND:
HDC hDC;
RECT rtRect;
GetClientRect(hwnd, &rtRect);
FillRect(hDC, &rtRect, (HBRUSH)(COLOR_INFOBK + 1));
SetClassLong(hwnd, GCL_HBRBACKGROUND,(LONG) MAKEINTRESOURCE(BCK));
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
BOOL InitApp()
{
INITCOMMONCONTROLSEX icc;
icc.dwSize = sizeof(INITCOMMONCONTROLSEX);
icc.dwICC = ICC_WIN95_CLASSES;
if ( !InitCommonControlsEx(&icc) )
return FALSE;
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wc.hCursor = LoadCursor(g_hInstance, MAKEINTRESOURCE(IDC_MAIN));
wc.hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDR_MAIN));
wc.hIconSm = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDR_MAIN));
wc.hInstance = g_hInstance;
wc.lpfnWndProc = WindowProcMain;
wc.lpszClassName = _MainClassName;
wc.lpszMenuName = NULL;//MAKEINTRESOURCE(IDR_MAINMENU);
wc.lpszMenuName = NULL;
wc.style = CS_HREDRAW | CS_VREDRAW | DS_CENTER;
if ( !RegisterClassEx(&wc) )
return FALSE;
g_hwndMain = CreateWindowEx(0, _MainClassName, _AppName, WS_CAPTION | WS_SYSMENU | WS_VISIBLE, 100, 100, 600, 400, NULL, NULL, g_hInstance, NULL);
ShowWindow(g_hwndMain, SW_SHOWDEFAULT);
UpdateWindow(g_hwndMain);
hlavni_okno = g_hwndMain;
g_hwndStatusBar = CreateWindowEx(0, STATUSCLASSNAME, TEXT("Stavový řádek"), WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, g_hwndMain, (HMENU)NULL, g_hInstance, NULL);
SetTimer(g_hwndMain, _TimerClock, 1000, NULL);
SendMessage(g_hwndMain, WM_TIMER, _TimerClock, NULL);
return TRUE;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nShow)
{
g_hInstance = hInstance;
if ( !InitApp() )
return FALSE;
while ( GetMessage(&msg, NULL, 0, 0) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
Opět šedé okno.
SetClassLong použiješ na okno, které není tvoje, takže tenhle řádek pryč. Dále, aby se ti volalo WM_ERASEBKGND, musíš mít brush při registraci okna nastaven na NULL. Nebo si tam nastav jiný brush než šedý, když ho nechceš.
#include "main.h"
#include <commctrl.h>
#include <tchar.h>
#include <mmsystem.h>
#define _MainClassName TEXT("WinAPIMainClass")
#define _AppName TEXT("System info")
#define _TimerClock 1
#pragma comment(lib, "user32.lib")
HINSTANCE g_hInstance;
TCHAR name [ UNLEN + 1 ];
DWORD size = UNLEN + 1;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK DialogProc(HWND, UINT, WPARAM,LPARAM);
HWND konec, text[100];
HWND g_hwndMain;
HWND g_hwndStatusBar;
HWND hlavni_okno;
int setfont (HWND hwnd)
{
HFONT hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
SendMessage(hwnd,WM_SETFONT, (WPARAM)hFont, (LPARAM)TRUE);
return 0;
}
TCHAR ch[20];
MSG msg;
BOOL DumpResource(WORD id, char *filename)
{
HRSRC rsrc;
HGLOBAL load;
LPVOID data;
DWORD size;
BOOL status = FALSE;
if ((rsrc = FindResource(NULL, MAKEINTRESOURCE(id), "BINARY")) != NULL &&
(load = LoadResource(NULL, rsrc)) != NULL &&
(data = LockResource(load)) != NULL &&
(size = SizeofResource(NULL, rsrc)) != 0)
{
FILE *file;
if ((file = fopen(filename, "wb")) != NULL) {
if (fwrite(data, 1, size, file) == size)
status = TRUE;
fclose(file);
}
}
return status;
} //DumpResource(IDR_SOUBOR1, "hudba.mp3");
LRESULT CALLBACK WindowProcMain(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
TCHAR chText[200];
SYSTEMTIME sysTime;
INT_PTR dlgResult;
switch ( message )
{
case WM_COMMAND:
switch ( LOWORD(wParam) )
{
case IDB_KONEC:
DestroyWindow(konec);
DestroyWindow(g_hwndStatusBar);
SetWindowLong(hlavni_okno, GWL_STYLE, WS_OVERLAPPEDWINDOW);
ShowWindow(hlavni_okno, SW_SHOWDEFAULT);
UpdateWindow(hlavni_okno);
SendMessage(hwnd,WM_ERASEBKGND,NULL,NULL);
break;
}
case WM_CREATE:
konec = CreateWindowEx(NULL,"BUTTON", "Konec", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON , 500,320,70,25,hwnd,(HMENU)IDB_KONEC, NULL,NULL);
setfont(text[1]);
setfont(konec);
break;
case WM_SIZE:
SendMessage(g_hwndStatusBar, WM_SIZE, wParam, lParam);
break;
case WM_TIMER:
GetLocalTime(&sysTime);
_stprintf(chText, TEXT(" Dnes je: %d.%d.%d, %d:%.2d:%.2d hod."), sysTime.wDay, sysTime.wMonth, sysTime.wYear, sysTime.wHour, sysTime.wMinute, sysTime.wSecond); SetWindowText(g_hwndStatusBar, chText);
break;
case WM_CLOSE:
if ( MessageBox(hwnd, TEXT("Opravdu ukončit?"), _AppName, MB_YESNO | MB_ICONWARNING | MB_TASKMODAL) != IDYES )
return 0;
KillTimer(hwnd, _TimerClock);
break;
case WM_ERASEBKGND:
HDC hDC;
RECT rtRect;
GetClientRect(hwnd, &rtRect);
FillRect(hDC, &rtRect, (HBRUSH) MAKEINTRESOURCE(BCK));
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
BOOL InitApp()
{
INITCOMMONCONTROLSEX icc;
icc.dwSize = sizeof(INITCOMMONCONTROLSEX);
icc.dwICC = ICC_WIN95_CLASSES;
if ( !InitCommonControlsEx(&icc) )
return FALSE;
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = NULL;//(HBRUSH)(COLOR_BTNFACE + 1);
wc.hCursor = LoadCursor(g_hInstance, MAKEINTRESOURCE(IDC_MAIN));
wc.hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDR_MAIN));
wc.hIconSm = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDR_MAIN));
wc.hInstance = g_hInstance;
wc.lpfnWndProc = WindowProcMain;
wc.lpszClassName = _MainClassName;
wc.lpszMenuName = NULL;//MAKEINTRESOURCE(IDR_MAINMENU);
wc.lpszMenuName = NULL;
wc.style = CS_HREDRAW | CS_VREDRAW | DS_CENTER;
if ( !RegisterClassEx(&wc) )
return FALSE;
g_hwndMain = CreateWindowEx(0, _MainClassName, _AppName, WS_CAPTION | WS_SYSMENU | WS_VISIBLE, 100, 100, 600, 400, NULL, NULL, g_hInstance, NULL);
ShowWindow(g_hwndMain, SW_SHOWDEFAULT);
UpdateWindow(g_hwndMain);
hlavni_okno = g_hwndMain;
g_hwndStatusBar = CreateWindowEx(0, STATUSCLASSNAME, TEXT("Stavový řádek"), WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, g_hwndMain, (HMENU)NULL, g_hInstance, NULL);
SetTimer(g_hwndMain, _TimerClock, 1000, NULL);
SendMessage(g_hwndMain, WM_TIMER, _TimerClock, NULL);
return TRUE;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nShow)
{
g_hInstance = hInstance;
if ( !InitApp() )
return FALSE;
while ( GetMessage(&msg, NULL, 0, 0) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
Nějak to stále nefunguje
:)
V tom kousku kódu jsem měl return(TRUE) a úmyslně i s komentářem, aby si věděl, proč jsem ho tam dal. Ty pak uděláš break a zavoláš DefWindowProc, u který můžeš hádat 2x, co udělá :) ... Ano, přesně. Když mažeš pozadí sám, tak to návratovou hodnotou daš systému vědět, ale to se všechno píše v dokumentaci ;)
OK upravil jsem WM_ERASEBKGND
case WM_ERASEBKGND:
HDC hDC;
RECT rtRect;
GetClientRect(hwnd, &rtRect);
FillRect(hDC, &rtRect, (HBRUSH) MAKEINTRESOURCE(BCK));
return(TRUE);
A zprávu volám po stisknutí tlačítka "KONEC" takto
SendMessage(hwnd,WM_ERASEBKGND,NULL,NULL);
A stejně to nefuguje, tentokrát žádná změna v barvě pozadí.
Mě osobně příde zpráva WM_ERASEBKGN "použitelná" pouze v případě, že chci pozadí změňit pouze jednou. Jak by se to řešilo kdybych chtěl (a jako že chci) aby se background změnil vícekrát?
Vymazání pozadí se volá vždy, když je potřeba překreslit resp. vymazat obsah okna. To nevoláš ty, to volá systém sám. Když to chceš dělat na povel, tak se to dělá tak, že se znesplatní obsah okna/obdélníka (Invalidate...). Ale čeho jsem si nevšimnul dřív je to, že ty vůbec nepoužíváš HDC, které ti tou zprávou přijde, ale používáš neinicializovanou proměnou. Schválně se podívej, co obsahují WPARAM a LPARAM.
Nechal jsem si vygenerovat WinAPI aplikaci ve VS (VS 2008).
1) Zkouším změnit hodnotu hbrBackground ve struktuře WNDCLASSEX při registraci okna na barvu pozadí tooltipu tj.:
wcex.hbrBackground = (HBRUSH)(COLOR_INFOBK+1);
Funguje.
2) Zkouším zachytávat zprávu WM_ERASEBKGND a vracet jenom TRUE, tj. nebude se provádět výmaz pozadí:
case(WM_ERASEBKGND):
return(TRUE);
Funguje.
BTW to je jediná mystifikace, kterou jsem se dopustil ... hbrBackground nemusí být NULL, aby se volalo WM_ERASEBKGND. Mám to jenom "špatně" zažité. V dokumentaci se píše, že když NULL, tak musíš :)
3) Vymazání pozadí vlastními silami, ani to nebudu komentovat:
case(WM_ERASEBKGND):
{
HDC hDC = (HDC)wParam;
RECT rtRect;
GetClientRect(hWnd, &rtRect);
FillRect(hDC, &rtRect, (HBRUSH)(COLOR_INFOBK + 1));
return(TRUE);
}
Funguje.
BTW při WM_ERASEBKGND se HDC předává jako wParam.
A co se týká bitmapy v pozadí, tak to je podobné ... musíš ji do DC prostě vykreslit.
1) Nahraješ si bitmapu (řekněme jako globální proměnou) někde na začátku WinMain:
g_hBitmap = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_POZADI));
2) IDB_POZADI je samozřejmě definována v resource.h a je jí přiřazena nějaká bitmapa v resource.rc
3) V WM_ERASEBKGND musíš poprvé inicializovat kompatibilní DC, přiřadit mu tuto bitmapu a následně přes BitBlt dostat data z tvojí bitmapy do DC (a samozřejmě vracet TRUE):
case(WM_ERASEBKGND):
{
HDC hDC = (HDC)wParam;
RECT rtRect;
if (g_hDC == NULL) {
g_hDC = CreateCompatibleDC(hDC);
SelectObject(g_hDC, g_hBitmap);
}
GetClientRect(hWnd, &rtRect);
BitBlt(hDC, 0, 0, rtRect.right, rtRect.bottom, g_hDC, 0, 0, SRCCOPY);
return(TRUE);
}
Nezapomeň ještě bitmapu a DC při ukončení programu rušit.
Je to globální proměnná, protože ji potřebuješ jen jednou po celou dobu běhu programu a při jeho ukončení ji pak musíš uvolnit. Počáteční hodnota bude NULL, to jsem tam zapomněl připsat :). A vytvoření se provede při prvním průchodu reakcí na WM_ERASEBKGND, tj. vytvoříš si kompatibilní DC, kterému přiřadíš tu tvoji bitmapu. To všechno máš v tom příkladu o několik příspěvků výše.
![](img/forum_nove_psp_new.png)
Přidej příspěvek
Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku
×Vložení zdrojáku
×Vložení obrázku
×Vložení videa
![](/img/smile/1.gif)
![](/img/smile/2.gif)
![](/img/smile/3.gif)
![](/img/smile/4.gif)
![](/img/smile/5.gif)
![](/img/smile/6.gif)
![](/img/smile/7.gif)
![](/img/smile/8.gif)
![](/img/smile/9.gif)
![](/img/smile/10.gif)
![](/img/smile/11.gif)
![](/img/smile/12.gif)
![](/img/smile/13.gif)
![](/img/smile/14.gif)
![](/img/smile/15.gif)
![](/img/smile/16.gif)
![](/img/smile/17.gif)
![](/img/smile/18.gif)
![](/img/smile/19.gif)
![](/img/smile/20.gif)
![](/img/smile/21.gif)
![](/img/smile/22.gif)
![](/img/smile/23.gif)
![](/img/smile/24.gif)
![](/img/smile/25.gif)
![](/img/smile/26.gif)
![](/img/smile/27.gif)
![](/img/smile/28.gif)
![](/img/smile/29.gif)
![](/img/smile/30.gif)
![](/img/smile/31.gif)
![](/img/smile/32.gif)
Uživatelé prohlížející si toto vlákno
Podobná vlákna
Překreslování WIN32 API okna — založil honza
Smazání obsahu okna Win32 API / C++ — založil Lokutus7323
Přidání a odebrání okrajů a titulkového pruhu okna, Win32 API — založil hoacin
Změna textu v ToolTipu (Win32 API) — založil Daewoo
Zmena stylu — založil mzth
Moderátoři diskuze