i'm trying to make a custom windows 8 style button using windows C API. however when i try to draw the text on the button after i redraw the button nothing visible happens!
I even tried creating a static window as a child of the button and sending WS_ERASEBKGND message to it when i redraw the button but as soon as i redraw the button for the first time it disappears!
here is the window procedure for my custom button:
LRESULT CALLBACK ButtonWindowProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
//static HWND static_text_handle;
HDC hdc;
PAINTSTRUCT ps;
DWORD color;
HFONT font,holdFont;
static RECT rect;
wchar_t test[] = L"test";
TRACKMOUSEEVENT tme = {sizeof(TRACKMOUSEEVENT),TME_LEAVE,hwnd,HOVER_DEFAULT};
/*static*/ HBRUSH brush = CreateSolidBrush(RGB(20,30,40));
/*static*/ HBRUSH clicked_brush = CreateSolidBrush(RGB(40,50,60));
/*static*/ HBRUSH hover_brush = CreateSolidBrush(RGB(70,80,90));
//TrackMouseEvent(&tme);
switch(msg)
{
case WM_CREATE:
//static_text_handle = CreateWindowW(L"Static",L"test",WS_CHILD | WS_VISIBLE,0,0,20,20,hwnd,NULL,NULL,NULL);
//brush = ((struct custom_button_colors*)(lParam))->default_color;
//clicked_brush = ((struct custom_button_colors*)(lParam))->push_color;
//hover_brush = ((struct custom_button_colors*)(lParam))->hover_color;
break;
case WM_LBUTTONDOWN:
SendMessage(hwnd,WM_ERASEBKGND,(WPARAM)GetDC(hwnd),(LPARAM)LPARAM_L_DOWN);
break;
case WM_LBUTTONUP:
SendMessage(hwnd,WM_ERASEBKGND,(WPARAM)GetDC(hwnd),(LPARAM)LPARAM_L_UP);
break;
case WM_MOUSEMOVE:
//Beep(1000,1000);
TrackMouseEvent(&tme);
if (GetAsyncKeyState(VK_LBUTTON))
{
SendMessage(hwnd,WM_ERASEBKGND,(WPARAM)GetDC(hwnd),(LPARAM)LPARAM_L_DOWN);
}
else
{
SendMessage(hwnd,WM_ERASEBKGND,(WPARAM)GetDC(hwnd),(LPARAM)LPARAM_MOUSEHOVER);
}
break;
case WM_MOUSELEAVE:
SendMessage(hwnd,WM_ERASEBKGND,(WPARAM)GetDC(hwnd),(LPARAM)-1);
break;
case WM_ERASEBKGND:
GetClientRect(hwnd,&rect);
if (lParam == LPARAM_L_DOWN)
{
FillRect((HDC)wParam,&rect,clicked_brush);
}
else if (lParam == LPARAM_MOUSEHOVER)
{
FillRect((HDC)wParam,&rect,hover_brush);
break;
}
else
{
POINT mousepos;
GetCursorPos(&mousepos);
if (WindowFromPoint(mousepos) == hwnd)
{
FillRect((HDC)wParam,&rect,hover_brush);
}
else
{
FillRect((HDC)wParam,&rect,brush);
}
}
hdc = BeginPaint(hwnd,&ps);
color = GetSysColor(COLOR_BTNFACE);
SetBkColor(hdc,color);
font = CreateFontW(25, 0, 0, 0, FW_MEDIUM, 0, 0, 0, 0,0, 0, ANTIALIASED_QUALITY, 0, L"Tahoma");
holdFont = SelectObject(hdc, font);
TextOutW(hdc,200,200,test,lstrlenW(test));
SelectObject(hdc,holdFont);
DeleteObject(font);
EndPaint(hwnd,&ps);
break;
default:
return DefWindowProc(hwnd,msg,wParam,lParam);
}
return 0;
}
I'm an absolute beginner in windows programming so sorry if my question is trivial.
1) Do not use BeginPaint/EndPaint in WM_ERASEBKGND. Move that code in a WM_PAINT handler.
2) Use SetWindowLong and the GWL_USERDATA index for storing the button state (UP or DOWN) and use GetWindowLong for retrieving the current state.
3) Use SetCapture for capturing the mouse, starting with WM_LBUTTONDOWN. Update the state of the button (UP or DOWN) according to mouse position
4) Use RedrawWindow when you need painting to occur
Related
I am trying to send a custom message (WM_APP + 1) when WM_SIZE is send to the window procedure. I want to be able to catch it from an other function using PeekMessage and do somethings. But when I test it the messages seem to not be send to the queue. Adding some printf statements shows me that it goes to the window procedure. The weird thing is that when I step through the code in the debugger it works fine but when I'm running normally, it goes back to not working.
Working example program with the problem, resize the window to test:
#include <windows.h>
#include <stdio.h>
#pragma comment(lib, "user32.lib")
#define OBG_EVENT_QUIT 0
#define OBG_EVENT_RESIZE 1
#define OBG_EVENT_NO -1
#define OBG_EVENT_UNKNOWN -2
//user defined event
#define OBG_WM_RESIZE (WM_APP + 1)
typedef union
{
int type;
struct
{
int type;
int width;
int height;
} resizeEvent;
} obg_event;
LRESULT CALLBACK obgpf_DefaultWindowCallback(HWND window, UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT result = 0;
switch(message)
{
case WM_CLOSE:
{
PostMessageA(window, WM_QUIT, 0, 0);
} break;
//this should be handled by OBGGetEvent
case OBG_WM_RESIZE:
{
printf("MESSAGE WENT THROUGH. DON'T WANT THIS\n");
} break;
case WM_SIZE:
{
PostMessageA(window, OBG_WM_RESIZE, wParam, lParam);
} break;
default:
{
result = DefWindowProc(window, message, wParam, lParam);
} break;
}
return result;
}
int OBGGetEvent(obg_event *event)
{
int moreMessages = 0;
MSG message;
if(PeekMessage(&message, 0, 0, 0, PM_REMOVE))
{
moreMessages = 1;
switch(message.message)
{
case WM_QUIT:
{
event->type = OBG_EVENT_QUIT;
} break;
case OBG_WM_RESIZE:
{
event->type = OBG_EVENT_RESIZE;
event->resizeEvent.type = OBG_EVENT_RESIZE;
event->resizeEvent.width = LOWORD(message.lParam);
event->resizeEvent.height = HIWORD(message.lParam);
} break;
default:
{
event->type = OBG_EVENT_UNKNOWN;
TranslateMessage(&message);
DispatchMessage(&message);
} break;
}
}
else
{
event->type = OBG_EVENT_NO;
}
return moreMessages;
}
int main()
{
HINSTANCE instance = GetModuleHandleA(0);
WNDCLASSEX windowClass = {0};
windowClass.cbSize = sizeof(windowClass);
windowClass.style = CS_HREDRAW | CS_VREDRAW;
windowClass.lpfnWndProc = obgpf_DefaultWindowCallback;
windowClass.hInstance = instance;
windowClass.lpszClassName = "testClass";
windowClass.hIcon = LoadIcon(0, IDI_APPLICATION);
windowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
windowClass.hIconSm = LoadIcon(0, IDI_APPLICATION);
windowClass.hCursor = LoadCursorA(0, IDC_ARROW);
HWND window;
if(RegisterClassEx(&windowClass))
{
window = CreateWindowEx(0,
windowClass.lpszClassName,
"test window",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
500,
300,
0,
0,
instance,
0);
if(window)
{
int appIsRunning = 1;
obg_event event = {0};
event.type = -1;
while(appIsRunning)
{
while(OBGGetEvent(&event))
{
if(event.type == OBG_EVENT_QUIT)
{
printf("event quit\n");
appIsRunning = 0;
break;
}
else if(event.type == OBG_EVENT_RESIZE)
{
printf("window resized: width %d height %d\n", event.resizeEvent.width, event.resizeEvent.height);
}
}
Sleep(33);
}
}
else
{
printf("window error\n");
}
}
else
{
printf("windowClass error\n");
}
return 0;
}
I tried doing this with SendMessage instead of PeekMessage but the same thing happened. Not sure what I'm missing or misunderstanding but any help is appreciated!
EDIT: added a complete working program that reproduces the problem
Thank you for the example code.
The behaviour you're seeing is because when the window is being resized using the mouse, the OS enters a modal message loop to process mouse input. During this loop, your message loop doesn't run - which means your PeekMessage() and the special message handling doesn't run either. Instead, messages are simply dispatched as normal to your window procedure.
There are two solutions that come to mind immediately but how you deal with this really depends on the design of your program and why you want to process size events in this way.
The first idea I had is to keep track of whether you're in a modal sizing loop or not, and defer posting the notification message until the loop is finished. An example of how to do that using your provided window procedure is below.
The second solution is to simply call your resize event handler directly whenever you get WM_SIZE (or, if you must go through the event system, put the handler for it in the window procedure rather than using PostMessage).
Example code for the first suggestion:
LRESULT CALLBACK obgpf_DefaultWindowCallback(HWND window, UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT result = 0;
static bool fResized = false;
static bool fInSizeLoop = false;
switch(message)
{
case WM_CLOSE:
{
PostMessageA(window, WM_QUIT, 0, 0);
} break;
//this should be handled by OBGGetEvent
case OBG_WM_RESIZE:
{
printf("MESSAGE WENT THROUGH. DON'T WANT THIS\n");
} break;
case WM_SIZE:
{
if (fInSizeLoop) // in modal size loop, defer notification
fResized = true;
else
PostMessageA(window, OBG_WM_RESIZE, wParam, lParam);
} break;
case WM_ENTERSIZEMOVE:
fInSizeLoop = true; // begin modal size loop
break;
case WM_EXITSIZEMOVE:
fInSizeLoop = false; // left modal size loop
// post resize notification now
if (fResized) {
RECT rc;
GetClientRect(window, &rc);
PostMessageA(window, OBG_WM_RESIZE, 0, MAKELPARAM(rc.right - rc.left, rc.bottom - rc.top));
fResized = false;
}
break;
default:
{
result = DefWindowProc(window, message, wParam, lParam);
} break;
}
return result;
}
(sorry, this is C++ code and I just noticed you had tagged as C - but the principle is the same).
I'm not sure what I'm doing wrong, but here's how it looks (there's no close button, no caption bar):
It looks as if it's not updating/ticking/repainted.
Here's my Resource.rc file:
#include "resource.h"
#include "windows.h"
#define IDC_STATIC -1
ID_ICON_MAIN ICON "Smile.ico"
ID_DIALOG_ABOUT DIALOG 0, 0, 240, 70
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_BORDER
CAPTION "About"
FONT 8, "Terminal"
{
DEFPUSHBUTTON "&OK", IDOK, 174, 18, 50, 14
PUSHBUTTON "&Cancel", IDCANCEL, 174, 36, 50, 14
GROUPBOX "About this program...", IDC_STATIC, 7, 7, 225, 52
CTEXT "An example program\r\nBy vexe", IDC_STATIC, 16, 18, 144, 33
}
Changing the styles, caption, font size, etc doesn't change anything. Note that I'm using Windows Classic Theme, changing to the standard Windows 7 doesn't help either so it's not a theme issue.
Here's my window code:
#include <Windows.h>
#include "resource.h"
INT_PTR WINAPI DialogWndProc(HWND Window, UINT Message,
WPARAM WParam, LPARAM LParam)
{
INT_PTR Result = TRUE;
switch (Message)
{
case WM_INITDIALOG:
{
// UpdateWindow(Window); // Doesn't really help. Taking out the case didn't do anything either
}
break;
case WM_COMMAND:
{
int Command = LOWORD(WParam);
switch(Command)
{
case IDOK:
{
EndDialog(Window, IDOK);
}
break;
case IDCANCEL:
{
EndDialog(Window, IDCANCEL);
}
break;
default:
{
Result = FALSE;
}
break;
}
}
break;
}
return(Result);
}
LRESULT WINAPI MainWndProc(HWND Window, UINT Message,
WPARAM WParam, LPARAM LParam)
{
LRESULT Result = 0;
switch (Message)
{
// (Causes GetMessage to return false)
case WM_CLOSE:
{
DestroyWindow(Window);
}
break;
case WM_DESTROY:
{
PostQuitMessage(0);
}
break;
case WM_COMMAND:
{
int Command = LOWORD(WParam);
switch (Command)
{
case ID_MENU_FILE_EXIT:
{
PostMessage(Window, WM_QUIT, 0, 0);
}
break;
case ID_MENU_HELP_ABOUT:
{
int Choice = DialogBox(0, MAKEINTRESOURCE(ID_DIALOG_ABOUT), Window, DialogWndProc);
switch (Choice)
{
case IDOK: MessageBox(Window, "Okay!", "OK", MB_OK | MB_ICONINFORMATION); break;
case IDCANCEL: MessageBox(Window, "Canceled!", "Cancel", MB_OK | MB_ICONINFORMATION); break;
}
}
break;
}
}
break;
case WM_CREATE:
{
HMENU Menu;
HMENU SubMenu;
// Create the main menu
Menu = CreateMenu();
// Create submenus
{
SubMenu = CreatePopupMenu();
AppendMenu(SubMenu, MF_STRING, ID_MENU_FILE_EXIT, "E&xit");
AppendMenu(Menu, MF_STRING | MF_POPUP, (UINT_PTR)SubMenu, "&File");
SubMenu = CreatePopupMenu();
AppendMenu(SubMenu, MF_STRING, ID_MENU_HELP_ABOUT, "&About");
AppendMenu(Menu, MF_STRING | MF_POPUP, (UINT_PTR)SubMenu, "&Help");
}
// Set the menu on the window
SetMenu(Window, Menu);
}
break;
default:
{
Result = DefWindowProc(Window, Message, WParam, LParam);
}
}
return(Result);
}
int CALLBACK WinMain(HINSTANCE Instance, HINSTANCE Previous, LPSTR CommandLine, int CmdShow)
{
// Create window class
WNDCLASSEX WindowClass = {0};
WindowClass.cbSize = sizeof(WNDCLASSEX);
WindowClass.style = CS_HREDRAW | CS_VREDRAW;
WindowClass.lpfnWndProc = (WNDPROC)MainWndProc;
WindowClass.hInstance = Instance;
WindowClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
WindowClass.lpszMenuName = MAKEINTRESOURCE(ID_MENU_MAIN);
WindowClass.lpszClassName = "SaedoGames_0";
WindowClass.hIcon = LoadIcon(Instance, MAKEINTRESOURCE(ID_ICON_MAIN));
WindowClass.hIconSm = (HICON)LoadImage(0, "Smile.ico", IMAGE_ICON, 16, 16, LR_LOADFROMFILE);
RegisterClassEx(&WindowClass);
// Create window
HWND Window = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, "SaedoGames_0", "Test Window",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT,
640, 480,
0, 0,
Instance, 0
);
// Show window
ShowWindow(Window, CmdShow);
UpdateWindow(Window);
// Message loop
MSG Msg;
while (GetMessage(&Msg, Window, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return(0);
}
Pretty sure I'm missing a simple function call but just not sure what it is. What am I missing?
Your dialog procedure unconditionally returns TRUE to every message, which means "I handled the message, you don't have to do anything else". Your dialog procedure does so by setting Result to TRUE at the top of the function and then never changing it (unless you get a WM_COMMAND from an unknown control). This is wrong; you need to return FALSE if you don't handle a message yourself.
WM_INITDIALOG is one of a handful of messages that return their values directly to the dialog system instead of through DWLP_MSGRESULT. In that case and that case only, you do need to return TRUE (unless you manually adjusted tab stops).
After enabling a disabled child window, I try to turn mouse tracking on in WM_ENABLE only if mouse cursor is hovering over the window using TrackMouseEvent() with dwFlags of TRACKMOUSEEVENT structure set to TME_LEAVE. TrackMouseEvent() returns TRUE, but then right after calling it I get a WM_MOUSELEAVE message. This happens only under 2 conditions. With first condition, move cursor outside of child window, press Enter key to disable the window, then move cursor over the child window and press the Space key. With second condition, move the cursor over window, press Enter key to disable it, then before pressing the Space key move the cursor 1 pixel or more and then press the Space key. If you retest the second condition, but instead of moving cursor before you press the Space key, if you press the Space key right after you press the Enter key, mouse tracking is turned on properly. I've tried really hard to fix this but I've not been lucky so far. Can somebody please fix this code and explain why mouse tracking is being canceled when I'm trying to turn it on?
#include <windows.h>
const WCHAR g_szChildClassName[] = L"Childclass////";
HINSTANCE g_hInst;
LRESULT CALLBACK ChildProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static BOOL bMouseTracking = FALSE;
switch(msg)
{
case WM_PAINT:
{
HDC hdc;
PAINTSTRUCT ps;
hdc = BeginPaint(hwnd, &ps);
if(hdc)
{
HBRUSH hbr = CreateSolidBrush(bMouseTracking?RGB(255, 0, 0):RGB(0, 0, 255));
if(hbr)
{
FillRect(hdc, &ps.rcPaint, hbr);
DeleteObject(hbr);
}
EndPaint(hwnd, &ps);
}
}
break;
case WM_MOUSEMOVE:
if(!bMouseTracking)
{
TRACKMOUSEEVENT tme = { 0 };
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = hwnd;
bMouseTracking = TrackMouseEvent(&tme);
InvalidateRect(hwnd, 0, TRUE);
}
break;
case WM_MOUSELEAVE:
bMouseTracking = FALSE;
InvalidateRect(hwnd, 0, TRUE);
break;
case WM_ENABLE:
if(wParam)
{
RECT rc;
if(GetWindowRect(hwnd, &rc))
{
POINT pt;
if(GetCursorPos(&pt))
if(PtInRect(&rc, pt))
{
TRACKMOUSEEVENT tme = { 0 };
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = hwnd;
//TrackMouseEvent() posts WM_MOUSELEAVE if conditions 1 and 2 are met, even though I'm trying to turn
//mouse tracking on and the cursor is over the child window. It doesn't make sense
//The problems is this piece of code right here /* bMouseTracking = TrackMouseEvent(&tme); */
//It should turn tracking on but it doesn't it cancels it even though WS_DISABLED has already been removed
//at this point
bMouseTracking = TrackMouseEvent(&tme);
InvalidateRect(hwnd, 0, TRUE);
}
}
} else {
if(bMouseTracking) {
////////If you comment everything from here ...
TRACKMOUSEEVENT tme = { 0 };
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE | TME_CANCEL;
tme.hwndTrack = hwnd;
//if(TrackMouseEvent(&tme)) PostMessage(hwnd, WM_MOUSELEAVE, 0, 0); //Commented this line out to do things a bit differently with the same results
if(TrackMouseEvent(&tme)) { //If this succeeds it means mouse tracking was canceled
bMouseTracking = FALSE;
InvalidateRect(hwnd, 0, TRUE);
}
////////all the way down to here the result is the same
//If you comment everything in this block out then you have another problem which can be tested with this condition:
//With window enabled move mouse over window, then press the ENTER key. The color should change
//from red to blue but it doesn't. It will change to blue though if you move the mouse 1 or more pixels after you've pressed the ENTER key
}
}
break;
case WM_DESTROY:
bMouseTracking = FALSE;
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HWND hChild;
switch(msg)
{
case WM_CREATE:
hChild = CreateWindowEx(0, g_szChildClassName, 0, WS_VISIBLE | WS_CHILD, 4, 4, 240, 80, hwnd, 0, g_hInst, 0);
break;
case WM_KEYDOWN:
if(wParam == VK_SPACE) EnableWindow(hChild, TRUE);
else if(wParam == VK_RETURN) EnableWindow(hChild, FALSE);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
const TCHAR szClassName[] = L"abccccccc";
WNDCLASSEX wc;
HWND hwnd;
MSG msg;
SecureZeroMemory(&wc, sizeof(WNDCLASSEX));
wc.cbSize = sizeof(WNDCLASSEX);
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
wc.hInstance = hInstance;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = szClassName;
if(!RegisterClassEx(&wc)) return 0; //Register main window class
SecureZeroMemory(&wc, sizeof(WNDCLASSEX));
wc.cbSize = sizeof(WNDCLASSEX);
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hInstance = hInstance;
wc.lpfnWndProc = ChildProc;
wc.lpszClassName = g_szChildClassName;
if(!RegisterClassEx(&wc)) return 0; //Register child window class
g_hInst = hInstance;
hwnd = CreateWindowEx(0, szClassName, L"Test", WS_OVERLAPPEDWINDOW, 40, 40, 420, 200, 0, 0, hInstance, 0);
if(!hwnd) return 0;
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while(GetMessage(&msg, 0, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
EDIT: You can't see the cursor in the pictures cause I used screen capture and it doesn't capture the cursor. In the first picture the cursor is outside of the child window and in the second picture the cursor is inside of the child window
ENTER key pressed when cursor is outside of child window
SPACE key pressed after the ENTER key was previously pressed and cursor is hovering over child window
I don't know if this is a shortcoming of the documentation or a bug in TrackMouseEvent, but it looks like TrackMouseEvent doesn't expect to be called within your WM_ENABLE handler.
To avoid that, try posting a message from WM_ENABLE and calling TrackMouseEvent from that:
case WM_ENABLE:
PostMessage(hwnd, WM_USER, wParam, lParam);
break;
case WM_USER:
if(wParam)
{
RECT rc;
if(GetWindowRect(hwnd, &rc))
{
POINT pt;
if(GetCursorPos(&pt))
if(PtInRect(&rc, pt))
{
TRACKMOUSEEVENT tme = { 0 };
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = hwnd;
//TrackMouseEvent() posts WM_MOUSELEAVE if conditions 1 and 2 are met, even though I'm trying to turn
//mouse tracking on and the cursor is over the child window. It doesn't make sense
//The problems is this piece of code right here /* bMouseTracking = TrackMouseEvent(&tme); */
//It should turn tracking on but it doesn't it cancels it even though WS_DISABLED has already been removed
//at this point
bMouseTracking = TrackMouseEvent(&tme);
InvalidateRect(hwnd, 0, TRUE);
}
}
} else {
if(bMouseTracking) {
////////If you comment everything from here ...
TRACKMOUSEEVENT tme = { 0 };
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE | TME_CANCEL;
tme.hwndTrack = hwnd;
//if(TrackMouseEvent(&tme)) PostMessage(hwnd, WM_MOUSELEAVE, 0, 0); //Commented this line out to do things a bit differently with the same results
if(TrackMouseEvent(&tme)) { //If this succeeds it means mouse tracking was canceled
bMouseTracking = FALSE;
InvalidateRect(hwnd, 0, TRUE);
}
////////all the way down to here the result is the same
//If you comment everything in this block out then you have another problem which can be tested with this condition:
//With window enabled move mouse over window, then press the ENTER key. The color should change
//from red to blue but it doesn't. It will change to blue though if you move the mouse 1 or more pixels after you've pressed the ENTER key
}
}
break;
I've got this code to open an InputBox defined on a DLL that get HMODULE that I save on hInstance variable when main program calls. How can I center it over the main program window?
It occurs that doesn't work and shows the DialogBox on top left on Screen or on top left of program window randomly.
#include <windows.h>
#include "resource.h"
char IB_res[10];
double defaultValue = 0;
BOOL CALLBACK InputBox_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_INITDIALOG:
if (defaultValue != -1)
SetDlgItemText(hwnd, IDC_EDIT, (LPCSTR)(my_printf("%f", defaultValue).c_str()));
else
SetDlgItemText(hwnd, IDC_EDIT, (LPCSTR)"");
return TRUE;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDOK:
if (!GetDlgItemText(hwnd, IDC_EDIT, IB_res, 10))
*IB_res = 0;
case IDCANCEL:
EndDialog(hwnd, wParam);
break;
}
break;
default:
return FALSE;
}
return TRUE;
}
DWORD processId;
HWND hwndParent;
BOOL CALLBACK enumWindowsProc(HWND hwnd, LPARAM lParam)
{
DWORD procid;
GetWindowThreadProcessId(hwnd, &procid);
if (procid == processId)
hwndParent = hwnd;
return TRUE;
}
HINSTANCE hInstance;
const char* InputBox(double def_value)
{
defaultBetValue = def_value;
processId = GetCurrentProcessId();
EnumWindows(enumWindowsProc, 0);
INT_PTR ret = DialogBox(hInstance, MAKEINTRESOURCE(IDD_IB), hwndParent, InputBox_WndProc);
DWORD error = GetLastError();
if (ret != IDOK)
*IB_res = 0;
return IB_res;
}
From:
http://msdn.microsoft.com/en-gb/library/windows/desktop/ms644996(v=vs.85).aspx
case WM_INITDIALOG:
// Get the owner window and dialog box rectangles.
if ((hwndOwner = GetParent(hwndDlg)) == NULL)
{
hwndOwner = GetDesktopWindow();
}
GetWindowRect(hwndOwner, &rcOwner);
GetWindowRect(hwndDlg, &rcDlg);
CopyRect(&rc, &rcOwner);
// Offset the owner and dialog box rectangles so that right and bottom
// values represent the width and height, and then offset the owner again
// to discard space taken up by the dialog box.
OffsetRect(&rcDlg, -rcDlg.left, -rcDlg.top);
OffsetRect(&rc, -rc.left, -rc.top);
OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom);
// The new position is the sum of half the remaining space and the owner's
// original position.
SetWindowPos(hwndDlg,
HWND_TOP,
rcOwner.left + (rc.right / 2),
rcOwner.top + (rc.bottom / 2),
0, 0, // Ignores size arguments.
SWP_NOSIZE);
if (GetDlgCtrlID((HWND) wParam) != ID_ITEMNAME)
{
SetFocus(GetDlgItem(hwndDlg, ID_ITEMNAME));
return FALSE;
}
return TRUE;
I want to make parent window as non transparent with RGB value as (99,99,99)? Previously my window was transparent but now i have requirement to make window as non transparent.
Mentioned below are the function related to my parent window:
ATOM MyRegisterClass(HINSTANCE hInstance)
{
LogEntry(L"Entered in myRegisterClass Function");
WNDCLASS CLASS_NAME_ONE_SEG_APP;
CLASS_NAME_ONE_SEG_APP.cbClsExtra = 0;
CLASS_NAME_ONE_SEG_APP.cbWndExtra = 0;
CLASS_NAME_ONE_SEG_APP.hbrBackground = 0;
CLASS_NAME_ONE_SEG_APP.hCursor = 0;
CLASS_NAME_ONE_SEG_APP.hIcon = 0;
CLASS_NAME_ONE_SEG_APP.hInstance = hInstance;
CLASS_NAME_ONE_SEG_APP.lpfnWndProc = (WNDPROC) WndProc;
CLASS_NAME_ONE_SEG_APP.lpszClassName = className;
CLASS_NAME_ONE_SEG_APP.lpszMenuName = 0;
CLASS_NAME_ONE_SEG_APP.style = 0;
LogEntry(L"Exiting from myRegisterClass Function");
return RegisterClass(&CLASS_NAME_ONE_SEG_APP);
}
Mentioned below is an InitInstance function in which i am creating the parent window.
handles.parent is my parent window.
bool WINAPI InitInstance(HINSTANCE hInstance, int nCmdShow)
{
LogEntry(L"Entered in InitInstance Function");
handles.parent = CreateWindowEx(0,
className,
windowName,
WS_VISIBLE | WS_POPUP,
0, 0,
coordinates.width, coordinates.height,
NULL,
NULL,
hInstance,
NULL);
if(handles.parent == NULL)
{
LogValue(L"Cannot Create Parent Window"
L"\nInitInstance Function terminated abnormally");
return false;
}
else
{
UpdateWindow(handles.parent);
ShowWindow(handles.parent, nCmdShow);
LogEntry(L"Exiting from InitInstance Function");
return true;
}
}
The below mentioned is a function for WM_PAINT:
case WM_PAINT:
LogEntry(L"Entred in WM_PAINT");
PaintWindow();
SetFocus(handles.parent);
LogEntry(L"Exited from WM_PAINT");
break;
This PaintWindow does the following.....
void PaintWindow()
{
LogEntry(L"Entered in PaintWindow Function");
HWND *handle = &handles.volUp;
//Paint Buttons on the window
for(register char i = MIN_BUTTON; i <= MAX_BUTTON; i++)
{
PaintButton( (INITIAL_BUTTON + i) , *handle, btns, i);
handle++;
}
//Paint the AXIS_VOL_ON_OFF Button According to its Status
if(volumeStatus.status == VOLUME_ON)
PaintButton(IDB_BTN_VOL_OFF, handles.volOnOff, btns, AXIS_VOL_ON_OFF);
else if(volumeStatus.status = VOLUME_MUTE)
PaintButton(IDB_BTN_VOL_ON, handles.volOnOff, btns, AXIS_VOL_ON_OFF);
//Paint Images on the window
if(handles.screenMode == SCREEN_MODE_OPERATION)
InsertImages();
LogEntry(L"Exited from PaintWindow Function");
}
Thanks in advance......
You need to give your class a non-null background brush
CLASS_NAME_ONE_SEG_APP.hbrBackground = CreateSolidBrush(RGB((99,99,99));
And in your WindowProc, you need to make sure that you pass the WM_ERASEBKGND message to DefWindowProc. (that part is probably already happening)
Later
Ok, your WM_PAINT code is doing some things wrong. It's important that you call BeginPaint and EndPaint when you handle the WM_PAINT message, and you have to use the HDC that you get from BeginPaint when you draw.
case WM_PAINT:
{
LogEntry(L"Entred in WM_PAINT");
PAINTSTRUCT ps;
HDC hdc = BeginPaint(&ps);
PaintWindow(hdc);
EndPaint(hwnd, &ps);
LogEntry(L"Exited from WM_PAINT");
}
break;
Your window is transparent because you never call BeginPaint in your WM_PAINT handler, so you never end up drawing anything to the screen.
See Drawing in the Client Area for a more complete example.