How do i detect the control that sent the WM_KEYDOWN? - winapi

WM_KEYDOWN message sends the message to the main window, I'd like to get control that originated the message. I've tried with GetFocus() handling WM_KEYDOWN like below but it didn't do anything, even when a press a key with focus on the buttona. How is that done? what am I missing?
Here's how I'm handling WM_KEYDOWN:
case WM_KEYDOWN:
HWND hFocus = GetFocus();
if(hFocus == buttonA)
{
buttona_onKeyDown();
}
else if(hFocus == buttonB)
{
buttonb_onKeyDown();
}
else
{
//MessageBox(NULL, L"Not found!", L"", MB_OK);
}
break;
full code:
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "Comctl32.lib")
#pragma comment(lib, "Gdi32.lib")
#define WIN32_LEAN_AND_MEAN
#define UNICODE
#define _UNICODE
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void buttona_onKeyDown();
void buttonb_onKeyDown();
HWND buttonA, buttonB;
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PWSTR lpCmdLine, int nCmdShow) {
MSG msg;
WNDCLASSW wc = {0};
wc.lpszClassName = L"Buttons";
wc.hInstance = hInstance;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpfnWndProc = WndProc;
wc.hCursor = LoadCursor(0, IDC_ARROW);
RegisterClassW(&wc);
HWND hWnd =
CreateWindowW(wc.lpszClassName, L"Buttons",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
150, 150, 300, 200, 0, 0, hInstance, 0);
while (GetMessage(&msg, NULL, 0, 0))
{
if (!IsDialogMessage(hWnd, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam) {
switch(msg)
{
case WM_CREATE:
buttonA =
CreateWindowW(L"Button", L"A",
WS_VISIBLE | WS_CHILD | WS_TABSTOP,
20, 50, 80, 25, hwnd, (HMENU) 10, NULL, NULL);
buttonB =
CreateWindowW(L"Button", L"B",
WS_VISIBLE | WS_CHILD | WS_TABSTOP,
120, 50, 80, 25, hwnd, (HMENU) 11, NULL, NULL);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_KEYDOWN:
HWND hFocus = GetFocus();
if(hFocus == buttonA)
{
buttona_onKeyDown();
}
else if(hFocus == buttonB)
{
buttonb_onKeyDown();
}
else
{
//MessageBox(NULL, L"Not found!", L"", MB_OK);
}
break;
}
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
void buttona_onKeyDown()
{
MessageBox(NULL, L"A OnKeyDown", L"", MB_OK);
}
void buttonb_onKeyDown()
{
MessageBox(NULL, L"B OnKeyDown", L"", MB_OK);
}

Related

Message after clicking on the edit control

I’m new to WinAPI development.
The main window contains three Edit controls.When clicking with the left mouse button on Edit1, the message "Edit1 choosed" is to be displayed. When you click on Edit2, it is supposed to display the message "Edit2 choosed". Similarly, when you click on Edit3, the message "Edit3 choosed" should be displayed. I tried using various combinations of WM_LBUTTONDOWN and WM_SETFOCUS, unfortunately the program does not work. Could someone please help me?
#include <windows.h>
#define Edit1 501
#define Edit2 502
#define Edit3 503
HWND TextBox1, TextBox2, TextBox3;
HFONT HF = CreateFont (30, 0, 00, 00, FW_DONTCARE, FALSE, FALSE, FALSE, ANSI_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, "Arial");
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
switch(Message)
{
case WM_SETFOCUS:
if(wParam == Edit1)
{
MessageBox(NULL, "Edit1 choosed","Edit1",MB_ICONEXCLAMATION|MB_OK);
}
break;
if(wParam == Edit2)
{
MessageBox(NULL, "Edit2 choosed","Edit2",MB_ICONEXCLAMATION|MB_OK);
}
break;
if(wParam == Edit3)
{
MessageBox(NULL, "Edit3 choosed","Edit3",MB_ICONEXCLAMATION|MB_OK);
}
break;
case WM_CREATE:
{
TextBox1 = CreateWindowEx( WS_EX_CLIENTEDGE, "EDIT", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_RIGHT,
30, 70, 190, 40, hwnd, (HMENU)Edit1, GetModuleHandle(NULL), NULL);
SendMessage(TextBox1, WM_SETFONT,( WPARAM ) HF, 0 );
TextBox2 = CreateWindowEx( WS_EX_CLIENTEDGE, "EDIT", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_RIGHT,
30, 130, 190, 40, hwnd, (HMENU)Edit2, GetModuleHandle(NULL), NULL);
SendMessage(TextBox2, WM_SETFONT,( WPARAM ) HF, 0 );
TextBox3 = CreateWindowEx( WS_EX_CLIENTEDGE, "EDIT", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_RIGHT,
30, 190, 190, 40, hwnd, (HMENU)Edit3, GetModuleHandle(NULL), NULL);
SendMessage(TextBox3, WM_SETFONT,( WPARAM ) HF, 0 );
break;
}
case WM_DESTROY:
{
PostQuitMessage(0);
break;
}
default:
return DefWindowProc(hwnd, Message, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG msg;
memset(&wc,0,sizeof(wc));
wc.cbSize = sizeof(WNDCLASSEX);
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszClassName = "WindowClass";
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&wc)) {
MessageBox(NULL, "Window Registration Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);
return 0;
}
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,"WindowClass","Caption",WS_VISIBLE|WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL,NULL,hInstance,NULL);
if(hwnd == NULL) {
MessageBox(NULL, "Window Creation Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);
return 0;
}
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
the "break" in the message loop under WM_SETFOCUS is always executed. So the program never reaches the point of the second edit control. Move the break to before the closing "}" and retry.
{
MessageBox(NULL, "Edit1 choosed","Edit1",MB_ICONEXCLAMATION|MB_OK);
break;
}
Furthermore, consider using 'else if'.

CreateWindow “Edit” typed characters are 'invisible'?

After having researched all I could find on the proper syntax for the CreateWindow("Edit") call, I have to throw in the towel: when I run the program, all I get in the Edit box is "invisible characters". The cursor is moving right as I type, but the characters I enter are nowhere to be seen. Only when I select the box content with the mouse do I see the text. But as soon as I release the mouse, I can not longer see anything.
Here is the entire code which leads to 'text not showing' in the Edit control:
#include <windows.h>
#define FILE_MENU_NEW 1
#define FILE_MENU_OPEN 2
#define FILE_MENU_QUIT 3
#define CHANGE_TITLE 4
LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM);
void AddMenus(HWND);
void AddControls(HWND);
HMENU hMenu;
HWND hEdit;
int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nShowCmd)
{
WNDCLASS wc = {0}; // Assign 0 to all its elements initialy
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hInstance = hInstance;
wc.lpszClassName = L"myWindowClass";
wc.lpfnWndProc = WindowProc; // this is a pointer to a function
if(!RegisterClass(&wc))
return -1;
HWND hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
L"myWindowClass",
L"Learn to Program Windows - Roger Breton",
WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
100, 100, 800, 600,
NULL,
NULL,
hInstance,
NULL
);
if (hwnd == NULL)
{
return 0;
}
MSG msg = { };
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_COMMAND:
switch(wParam)
{
case FILE_MENU_QUIT:
DestroyWindow(hWnd);
break;
case FILE_MENU_NEW:
MessageBeep(MB_ICONINFORMATION);
break;
case CHANGE_TITLE:
wchar_t text[100];
GetWindowTextW(hEdit, text, 100);
SetWindowTextW(hWnd, text);
break;
}
case WM_CREATE:
AddMenus(hWnd);
AddControls(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW));
EndPaint(hWnd, &ps);
}
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
void AddMenus(HWND hWnd)
{
hMenu = CreateMenu();
HMENU hFileMenu = CreateMenu();
HMENU hSubMenu = CreateMenu();
AppendMenu(hSubMenu, MF_STRING, NULL, L"Sub-Menu");
AppendMenu(hFileMenu, MF_STRING, FILE_MENU_NEW, L"New");
AppendMenu(hFileMenu, MF_POPUP, (UINT_PTR)hSubMenu, L"Sub-menu ");
AppendMenu(hFileMenu, MF_SEPARATOR, NULL, NULL);
AppendMenu(hFileMenu, MF_STRING, FILE_MENU_QUIT, L"Quit");
AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hFileMenu, L"File");
AppendMenu(hMenu, MF_STRING, NULL, L"Aide");
SetMenu(hWnd, hMenu);
}
void AddControls(HWND hWnd)
{
CreateWindowW(L"Static", L"Enter text here:", WS_VISIBLE | WS_CHILD | WS_BORDER | SS_CENTER , 200, 100, 150, 50, hWnd, NULL, NULL, NULL);
hEdit = CreateWindowW(L"Edit", NULL, WS_VISIBLE | WS_CHILD | WS_BORDER , 200, 152, 100, 50, hWnd, NULL, NULL, NULL);
CreateWindowW(L"Button", L"Changez title", WS_VISIBLE | WS_CHILD, 200, 204, 150, 50, hWnd, (HMENU)CHANGE_TITLE, NULL, NULL);
}
I tried to recreate the source file many times, to no avail.
You have a missing break; statement at the end of your case WM_COMMAND: block. As it stands, your code will 'fall through' to the case WM_CREATE: code after processing any WM_COMMAND.
Adding that break; statement appears to fix your code (when I test it):
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg) {
case WM_COMMAND:
switch (wParam) {
case FILE_MENU_QUIT:
DestroyWindow(hWnd);
break;
case FILE_MENU_NEW:
MessageBeep(MB_ICONINFORMATION);
break;
case CHANGE_TITLE:
wchar_t text[100];
GetWindowTextW(hEdit, text, 100);
SetWindowTextW(hWnd, text);
break;
}
break; // ** You missed this line! **
case WM_CREATE:
AddMenus(hWnd);
AddControls(hWnd);
break;
//...
Such mistakes can be spotted if you enable all compiler warnings: The static code analyser in MSVC gives the following message:
warning C26819: Unannotated fallthrough between switch labels (es.78).

How do I detect a WM_KEYDOWN on child window?

For a standard control like button, edit, etc I can subclass it but how is this done for a child window(I'm using as a container)? I know the WM_KEYDOWN is sent to the parent window but I couldn't get it directly from the respective child window. I've tried subclassing it(not sure if this does make sense since it's a window and has its own window procedure already in the WNDCLASSW.lpfnWndProc member) but this subprocedure didn't get a WM_KEYDOWN message anyway. I can get the control's hwnd from the cursor position (I need to consider keyboard focus too) by using GetCursorPos() and WindowFromPoint() like below but I feel it's hacky. What's the proper way to do this?
currently it look like this:
case WM_KEYUP:
case WM_KEYDOWN:
{
POINT p;
if(GetCursorPos(&p))
{
HWND control = WindowFromPoint(p);
if(control)
{
// just testing it
int len = GetWindowTextLength(control);
wchar_t buffer[len + 1];
GetWindowText(control, buffer, sizeof(buffer));
MessageBox(NULL, buffer, L"", MB_OK);
}
}
}
break;
the window look like this:
the goal is catch the WM_KEYDOWN on the respective window where the user typed something, then call a function to deal with this event, like window1_onKeyDown(), window2_onKeyDown() and such.
Here's full code:
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "Comctl32.lib")
#pragma comment(lib, "Gdi32.lib")
#define WIN32_LEAN_AND_MEAN
#define UNICODE
#define _UNICODE
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK WndProc1(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK WndProc2(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
void createWindow1(HWND);
void createWindow2(HWND);
HBRUSH hBrush1, hBrush2;
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PWSTR lpCmdLine, int nCmdShow) {
MSG msg;
WNDCLASSW wc = {0};
wc.lpszClassName = L"my window";
wc.hInstance = hInstance;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpfnWndProc = WndProc;
wc.hCursor = LoadCursor(0, IDC_ARROW);
hBrush1 = CreateSolidBrush(RGB(173, 164, 237));
hBrush2 = CreateSolidBrush(RGB(171, 171, 171));
RegisterClassW(&wc);
CreateWindowW(wc.lpszClassName, L"window",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
100, 100, 330, 270, NULL, 0, hInstance, 0);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
DeleteObject(hBrush1);
DeleteObject(hBrush2);
return (int) msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam) {
switch(msg)
{
case WM_CREATE:
createWindow1(hwnd);
createWindow2(hwnd);
break;
case WM_KEYUP:
case WM_KEYDOWN:
{
POINT p;
if(GetCursorPos(&p))
{
HWND control = WindowFromPoint(p);
if(control)
{
int len = GetWindowTextLength(control);
wchar_t buffer[len + 1];
GetWindowText(control, buffer, sizeof(buffer));
MessageBox(NULL, buffer, L"", MB_OK);
}
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
void createWindow1(HWND hOwner)
{
WNDCLASSW wc = {0};
wc.lpszClassName = L"window2";
wc.hInstance = NULL;
wc.hbrBackground = hBrush1;
wc.lpfnWndProc = WndProc1;
wc.hCursor = LoadCursor(0, IDC_ARROW);
RegisterClassW(&wc);
CreateWindowW(wc.lpszClassName, L"window2",
WS_VISIBLE | WS_TABSTOP | WS_CHILD | WS_EX_CONTROLPARENT,
5, 5, 200, 100,
hOwner, 0, NULL, 0);
}
void createWindow2(HWND hOwner)
{
WNDCLASSW wc = {0};
wc.lpszClassName = L"window3";
wc.hInstance = NULL;
wc.hbrBackground = hBrush2;
wc.lpfnWndProc = WndProc2;
wc.hCursor = LoadCursor(0, IDC_ARROW);
RegisterClassW(&wc);
CreateWindowW(wc.lpszClassName, L"window3",
WS_VISIBLE | WS_TABSTOP | WS_CHILD,
5, 120, 200, 100,
hOwner, 0, NULL, 0);
}
LRESULT CALLBACK WndProc1(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
CreateWindow(L"Button", L"Button A",
WS_VISIBLE | WS_TABSTOP | WS_CHILD,
5, 5, 80, 25,
hwnd, 0, NULL, 0);
break;
case WM_KEYUP:
case WM_KEYDOWN:
MessageBox(NULL, L"hello from proc1", L"", MB_OK);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
LRESULT CALLBACK WndProc2(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
CreateWindow(L"Button", L"Button ",
WS_VISIBLE | WS_TABSTOP | WS_CHILD,
5, 5, 80, 25,
hwnd, 0, NULL, 0);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
You can use SetFocus in the child window.
Some code:
case WM_KEYDOWN:
{
POINT p;
HWND control = GetFocus();
if (control)
{
int len = GetWindowTextLength(control);
wchar_t* buffer = new wchar_t[len + 1];
GetWindowText(control, buffer, len + 1);
MessageBox(NULL, buffer, L"", MB_OK);
}
}
break;
LRESULT CALLBACK WndProc1(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
CreateWindow(L"Button", L"Button A",
WS_VISIBLE | WS_TABSTOP | WS_CHILD,
5, 5, 80, 25,
hwnd, 0, NULL, 0);
break;
case WM_LBUTTONDOWN:
SetFocus(hwnd);
break;
case WM_KEYUP:
case WM_KEYDOWN:
MessageBox(NULL, L"hello from proc1", L"", MB_OK);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
You can also use the current method, and then use PostMessage/SendMessage to forward the WM_KEYDOWN message to the child window:
if (control)
{
int len = GetWindowTextLength(control);
wchar_t* buffer = new wchar_t[len + 1];
GetWindowText(control, buffer, len + 1);
MessageBox(NULL, buffer, L"", MB_OK);
PostMessage(hwnd_child, msg, wParam, lParam);
}

Sending message TVM_EDITLABEL fails

TreeView_EditLabel(tv, item) fails(returns zero).
item is valid, and is the only item in the treeview.
What's the problem? Is there some prerequisite? Or it just doesn't work?
I'm on Windows 10.
Here's a minimal reproducible example
#include <windowsx.h>
#include <CommCtrl.h>
#include <assert.h>
#pragma comment(lib, "Comctl32.lib")
HWND hTv;
HTREEITEM hItem;
auto className = L"someclass";
ATOM MyRegisterClass(HINSTANCE hInstance);
void InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
InitCommonControls();
MyRegisterClass(hInstance);
InitInstance(hInstance, nCmdShow);
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex{};
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.lpszClassName = className;
return RegisterClassExW(&wcex);
}
void InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd = CreateWindowW(className, L"", WS_OVERLAPPEDWINDOW, 400, 400, 400, 400, nullptr, nullptr, hInstance, nullptr);
assert(hWnd);
hTv = CreateWindowW(WC_TREEVIEW, L"Tree View", WS_VISIBLE | WS_CHILD | WS_BORDER | TVS_HASLINES, 0, 0, 300, 300, hWnd, 0, 0, NULL);
assert(hTv);
{
TVITEM tvi{};
TVINSERTSTRUCT tvins{};
tvi.mask = TVIF_TEXT;
wchar_t name[] = L"item";
tvi.pszText = name;
tvins.item = tvi;
hItem = TreeView_InsertItem(hTv, &tvins);
}
ShowWindow(hWnd, nCmdShow);
SetFocus(hTv);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_NOTIFY:
{
switch (reinterpret_cast<LPNMHDR>(lParam)->code)
{
case NM_CLICK:
assert(TreeView_EditLabel(hTv, hItem));
break;
}
break;
}
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
A tree-view control needs the TVS_EDITLABELS control style set to support editing labels of tree-view items.
You need to replace the tree-view control creation code
hTv = CreateWindowW(
WC_TREEVIEW,
L"Tree View",
WS_VISIBLE | WS_CHILD | WS_BORDER | TVS_HASLINES,
0, 0, 300, 300,
hWnd,
0,
0,
NULL);
with this:
hTv = CreateWindowW(
WC_TREEVIEW,
L"Tree View",
WS_VISIBLE | WS_CHILD | WS_BORDER | TVS_HASLINES | TVS_EDITLABELS,
0, 0, 300, 300,
hWnd,
0,
0,
NULL);
The tree-view controls overview overview provides additional details under the section titled tree-view label edition.

What is the correct designpattern for UI?

I am making a small app for loading data from an external device. It uses a DLL.
I want to make the app running in one window. With the menu it should be possible to bring up the correct state of UI. I dont want to use dialogs or seperate windows.
My idea is to use a state variable and have the WM_PAINT message handle the different content of the windows (createwindowEx for different text and button items i.e.).
Is this the correct way of doing so? I have searched the internet, read Programming Windows and searched stackoverflow and could not find a simple example. It is always using different windows with dedicated winproc functions. It feels like i dont need that...
Can someone help me with a direction or small example/link ?
thx
EDIT:
I enclose the code that i have so far now. Can someone have a look on that, Thx.
#if defined _MSC_VER || defined __BORLANDC__
#define OEMRESOURCE
#endif
#pragma comment(linker,"\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#include <windows.h> //include all the basics
#include <tchar.h> //string and other mapping macros
#include <iostream>
#include <string>
#include "hrmcom.h"
#include "resource.h"
typedef std::basic_string<TCHAR> ustring;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK ChildProc(HWND, UINT, WPARAM, LPARAM);
inline int ErrMsg(const ustring&);
bool CreateChild(HWND);
bool CreateChildScreen(HWND);
ustring classname = TEXT("MAINWND");
ustring childname = TEXT("CHILDWND");
HWND hwndChild[3], hwndCtrl[CTRNUM];
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR pStr, int nCmd)
{
WNDCLASSEX wcx = { 0 };
wcx.cbSize = sizeof(WNDCLASSEX);
wcx.lpfnWndProc = WndProc;
wcx.hInstance = hInst;
wcx.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON1));
wcx.hCursor = reinterpret_cast<HCURSOR>(LoadImage(0, IDC_ARROW,
IMAGE_CURSOR, 0, 0, LR_SHARED));
wcx.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_BTNFACE + 1);
wcx.lpszClassName = classname.c_str();
if (!RegisterClassEx(&wcx))
{
ErrMsg(_T("Failed to register wnd class"));
return -1;
}
wcx.lpfnWndProc = ChildProc;
wcx.cbWndExtra = sizeof (long);
wcx.hIcon = NULL;
wcx.lpszClassName = childname.c_str();
if (!RegisterClassEx(&wcx))
{
ErrMsg(_T("Failed to register wnd class"));
return -1;
}
HMENU hMenu = LoadMenu(hInst, MAKEINTRESOURCE(IDR_MENU));
HWND hwnd = CreateWindowEx(0,
classname.c_str(),
TEXT("Polar Loader"),
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU,
400, 200, 600, 300,
0,
hMenu,
hInst,
0);
if (!hwnd)
{
ErrMsg(TEXT("Failed to create wnd"));
return -1;
}
ShowWindow(hwnd, nCmd);
UpdateWindow(hwnd);
MSG msg;
while (GetMessage(&msg, 0, 0, 0)>0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return static_cast<int>(msg.wParam);
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
//Create the Childwindows
if (!CreateChild(hwnd))
{
ErrMsg(TEXT("Failed to create Childwindows"));
return -1;
}
//Create controls of the Childwindows
if (!CreateChildScreen(hwnd))
{
ErrMsg(TEXT("Failed to create Conrols of Childwindows"));
return -1;
}
return 0;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDM_Acc:
ShowWindow(hwndChild[0], SW_SHOW);
return 0;
case IDM_Con:
case IDM_Help:
case IDM_Log:
case IDM_Pol:
case IDM_Trans:
ShowWindow(hwndChild[0], SW_HIDE);
return 0;
}
case WM_DESTROY:
PostQuitMessage(0); //signal end of application
return 0;
default:
//let system deal with msg
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
LRESULT CALLBACK ChildProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
SetWindowLong(hwnd, 0, 0);
return 0;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case ID_CTRL+5:
MessageBeep(0);
return 0;
}
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
inline int ErrMsg(const ustring& s)
{
return MessageBox(0, s.c_str(), _T("ERROR"), MB_OK | MB_ICONEXCLAMATION);
}
bool CreateChild(HWND hwnd)
{
static int x;
for (x = 0; x < 3; x++)
{
hwndChild[x] = CreateWindowEx(0, childname.c_str(), NULL,
WS_CHILDWINDOW,
0, 0, 600, 300,
hwnd, (HMENU)x,
(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE),
NULL);
if (!hwndChild[x]) return FALSE;
}
return TRUE;
}
bool CreateChildScreen(HWND hwnd)
{
LPCWSTR lpType[CTRNUM] = { TEXT("static"), TEXT("edit"), TEXT("edit"), TEXT("static"), TEXT("static"), TEXT("button") };
LPCWSTR lpName[CTRNUM] = { TEXT("Log on to Gedysan Training App:"), TEXT(""), TEXT(""), TEXT("Username:"), TEXT("Password:"), TEXT("Log on") };
DWORD dStyle[CTRNUM] = { WS_CHILD | WS_VISIBLE | ES_LEFT,
WS_CHILD | WS_VISIBLE | ES_LEFT | WS_BORDER | ES_AUTOHSCROLL,
WS_CHILD | WS_VISIBLE | ES_LEFT | WS_BORDER | ES_PASSWORD | ES_AUTOHSCROLL,
WS_CHILD | WS_VISIBLE | ES_LEFT,
WS_CHILD | WS_VISIBLE | ES_LEFT,
WS_CHILD | WS_VISIBLE | ES_LEFT
};
RECT rc[CTRNUM] = { { 15, 10, 400, 25 }, { 100, 40, 150, 25 }, { 100, 70, 150, 25 }, { 15, 45, 70, 25 }, { 15, 75, 70, 25 }, { 15, 110, 70, 25 } };
int iChildNum[CTRNUM] = { 0, 0, 0, 0, 0, 0 };
static int x;
for (x = 0; x < CTRNUM; x++)
{
RECT x1 = rc[x];
hwndCtrl[x] = CreateWindowEx(0, lpType[x], lpName[x], dStyle[x],
x1.left, x1.top, x1.right, x1.bottom,
hwndChild[iChildNum[0]], (HMENU)(ID_CTRL + x),
(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), 0);
if (!hwndChild[x]) return FALSE;
}
return TRUE;
}
With your proposed approach you will get a bunch of unrelated stuff all in the WM_PAINT handler, making a messy design. When a menu selection is made you get a message. Run code related to that menu command in that message handler.
If your UI is composed of controls then WM_PAINT is not involved at all: Those controls do their own painting. Your WM_PAINT handler should do any custom painting you need, and nothing else.

Resources