Related
My goal is to create 5 groups of radio buttons (i know it contradict with the title but you still get the point) for user choice using only Win32 API (so no window form here).
I tried using a combination of groupbox and SetWindowLongPtr but it still not working as expected (note that im using GWLP_WNDPROC as the index). If i use SetWindowLongPtr to a group box then that groupbox is gone and everything else work as expected.
I could use a "virtual" group box but it reduce the efficency of my code. Some one might recommend using WS_GROUP but it only apply if there are 2 group of radio buttons ( I think ). And i also dont like using resource so is there any solution to this problem or i just have to stuck with the "virtual" group box?
Minimal reproducible sample:
#include <Windows.h>
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wp, LPARAM lp)
{
switch (uMsg)
{
default:
return DefWindowProc(hwnd, uMsg, wp, lp);
}
}
int WINAPI wWinMain(HINSTANCE hinst, HINSTANCE hiprevinst, PWSTR nCmdLine, int ncmdshow)
{
const wchar_t CLASS_NAME[] = L"Sample";
WNDCLASS wc = { };
wc.lpfnWndProc = WndProc;
wc.hInstance = hinst;
wc.lpszClassName = CLASS_NAME;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
RegisterClass(&wc);
HWND hwnd = CreateWindowEx(
0,
CLASS_NAME,
L"Sample window",
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, // Window style
CW_USEDEFAULT, CW_USEDEFAULT, 800, 600,
NULL,
NULL,
hinst,
NULL);
HWND groupbox = CreateWindowEx(0, L"Button", L"Groupbox", WS_VISIBLE | WS_CHILD | BS_GROUPBOX, 10, 10, 100, 100, NULL, NULL, hinst, NULL);
HWND radiobutton1 = CreateWindowEx(0, L"Button", L"Groupbox", WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON, 10, 10, 60, 60, groupbox, NULL, hinst, NULL);
SetWindowLongPtr(groupbox, GWLP_WNDPROC, (LONG)WndProc);
SendMessage(groupbox, NULL, NULL, TRUE);
ShowWindow(hwnd, ncmdshow);
MSG msg;
while (GetMessage(&msg, NULL, NULL, NULL))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
Due to i stripped so much of the necessary function away, you need to go to task manager and kill the process named "Autoclicker" for some reason to be able to recompile it again
Make sure you handle WM_DESTROY otherwise window won't close properly.
The radio buttons, all child dialog items, and all child windows should be created in WM_CREATE section of parent window. They need the HWND handle from parent window.
SetWindowLongPtr(.. GWLP_WNDPROC ...) is an old method used for subclassing. Your usage is incorrect. You don't need it anyway.
It's unclear what SendMessage(groupbox, NULL, NULL, TRUE); is supposed to do.
Just add the radio buttons, make sure the first radio button has an added WS_TABSTOP|WS_GROUP as shown below
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wp, LPARAM lp)
{
switch (uMsg)
{
case WM_CREATE:
{
HINSTANCE hinst = GetModuleHandle(0);
auto add = [&](const wchar_t* name,
int id, int x, int y, int w, int h, bool first = false)
{
DWORD style = WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON;
if (first) style |= WS_GROUP | WS_TABSTOP;
return CreateWindowEx(0, L"Button", name, style,
x, y, w, h, hwnd, (HMENU)id, hinst, NULL);
};
HWND groupbox1 = CreateWindowEx(0, L"Button", L"Groupbox1",
WS_VISIBLE | WS_CHILD | BS_GROUPBOX, 2, 2, 250, 120, hwnd, NULL, hinst, NULL);
HWND radio1 = add(L"radio1", 1, 10, 30, 200, 20, true);
HWND radio2 = add(L"radio2", 2, 10, 51, 200, 20);
HWND radio3 = add(L"radio3", 3, 10, 72, 200, 20);
HWND radio4 = add(L"radio4", 4, 10, 93, 200, 20);
HWND groupbox2 = CreateWindowEx(0, L"Button", L"Groupbox2",
WS_VISIBLE | WS_CHILD | BS_GROUPBOX, 280, 2, 250, 120, hwnd, NULL, hinst, NULL);
HWND radio11 = add(L"radio1", 11, 300, 30, 200, 20, true);
HWND radio12 = add(L"radio2", 12, 300, 51, 200, 20);
HWND radio13 = add(L"radio3", 13, 300, 72, 200, 20);
HWND radio14 = add(L"radio4", 14, 300, 93, 200, 20);
return 0;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, uMsg, wp, lp);
}
}
int WINAPI wWinMain(HINSTANCE hinst, HINSTANCE hiprevinst, PWSTR nCmdLine, int ncmdshow)
{
const wchar_t CLASS_NAME[] = L"Sample";
WNDCLASS wc = { };
wc.lpfnWndProc = WndProc;
wc.hInstance = hinst;
wc.lpszClassName = CLASS_NAME;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
RegisterClass(&wc);
HWND hwnd = CreateWindowEx(0, CLASS_NAME, L"Sample window",
WS_OVERLAPPEDWINDOW, 0, 0, 800, 600,
NULL, NULL, hinst, NULL);
ShowWindow(hwnd, ncmdshow);
MSG msg;
while (GetMessage(&msg, NULL, NULL, NULL))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
I'd like to create a Windows app consisting of a main parent window and several child windows. Here is an excerpt of the code I have so far:
...
// -----> CHILD WINDOWS <-----
HWND hWnd_child1 = CreateWindowW(L"STATIC", L"Child 1", WS_CHILD,
0, 0, 100, 80, hParentWnd, nullptr, hInstance, nullptr);
if (!hWnd_child1) {
MessageBox(NULL, L"CreateWindowW Child 1", L"Error!", MB_ICONEXCLAMATION | MB_OK);
return FALSE;
}
HWND hWnd_child2 = CreateWindowW(L"STATIC", L"Child 2", WS_CHILD,
10, 10, 160, 120, hParentWnd, nullptr, hInstance, nullptr);
if (!hWnd_child2) {
MessageBox(NULL, L"CreateWindowW Child 2", L"Error!", MB_ICONEXCLAMATION | MB_OK);
return FALSE;
}
HWND hWnd_child3 = CreateWindowW(L"STATIC", L"Child 3", WS_CHILD,
20, 20, 160, 120, hParentWnd, nullptr, hInstance, nullptr);
if (!hWnd_child3) {
MessageBox(NULL, L"CreateWindowW Child 3", L"Error!", MB_ICONEXCLAMATION | MB_OK);
return FALSE;
}
ShowWindow(hWnd_child3, nCmdShow);
SetWindowPos(hWnd_child2, HWND_TOP, 10, 10, 100, 80, NULL);
ShowWindow(hWnd_child2, nCmdShow);
SetWindowPos(hWnd_child1, HWND_TOP, 0, 0, 100, 80, NULL);
ShowWindow(hWnd_child1, nCmdShow);
ShowWindow(hParentWnd, nCmdShow);
UpdateWindow(hParentWnd);
// -------------------
...
The problem is with the SetWindowPos() function. I can't understand how it really works. I thought that calling it like this:
ShowWindow(hWnd_child3, nCmdShow);
SetWindowPos(hWnd_child2, HWND_TOP, 10, 10, 100, 80, NULL);
ShowWindow(hWnd_child2, nCmdShow);
SetWindowPos(hWnd_child1, HWND_TOP, 0, 0, 100, 80, NULL);
ShowWindow(hWnd_child1, nCmdShow);
Would move the Child 1 window to the top of all the app windows (as the doc says for the HWND_TOP option: Places the window at the top of the Z order).
BUT, the windows are still drawned in the creation order:
Shouldn't SetWindowPos() move firstly Child 2 over Child 3, and next Child 1 over Child 2, making the windows laid up in the reverse order than they were created, with Child 1 on top?
Make the child windows all have the window style WS_CLIPSIBLINGS along with WS_CHILD etc.
From Microsoft's documentation:
If WS_CLIPSIBLINGS is not specified and child windows overlap, it is
possible, when drawing within the client area of a child window, to
draw within the client area of a neighboring child window.
Basically if the child windows do not clip each other then the order in which they are painted (which is arbitrary) determines the visual z-order.
Below for instance is your code with the message box stuff removed, using WS_VISIBLE instead of ShowWindow, adding a border for visibility, and using WS_CLIPSIBLINGS.
BOOL CreateChildren(HWND hParentWnd) {
HWND hWnd_child1 = CreateWindowEx(WS_EX_CLIENTEDGE, L"STATIC", L"Child 1", WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS,
0, 0, 100, 80, hParentWnd, nullptr, g_hInstance, nullptr);
HWND hWnd_child2 = CreateWindowEx(WS_EX_CLIENTEDGE, L"STATIC", L"Child 2", WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS,
10, 10, 160, 120, hParentWnd, nullptr, g_hInstance, nullptr);
HWND hWnd_child3 = CreateWindowEx(WS_EX_CLIENTEDGE, L"STATIC", L"Child 3", WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS,
20, 20, 160, 120, hParentWnd, nullptr, g_hInstance, nullptr);
SetWindowPos(hWnd_child2, HWND_TOP, 10, 10, 100, 80, NULL);
SetWindowPos(hWnd_child1, HWND_TOP, 0, 0, 100, 80, NULL);
UpdateWindow(hParentWnd);
return TRUE;
}
which yields
child1 is on top.
I am able to add image to the button as background but later I want to add text to the button as "Weclome", I tried all possible ways using Settext, SendmessageA.
please help
#include <Windows.h>
int main()
{
MSG msg;
HWND hWnd = CreateWindow(TEXT("button"), TEXT("START"), WS_VISIBLE | WS_POPUP | WS_CHILD | WS_TABSTOP | BS_BITMAP,
250, 250, 500, 500, NULL, NULL, NULL, NULL);
HANDLE hImg = LoadImageW(NULL, L"Untitled.bmp", IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR | LR_DEFAULTSIZE | LR_LOADFROMFILE);
SendMessageW(hWnd, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hImg);
SendMessageA(hWnd, WM_SETTEXT, 0, (LPARAM)"Welcome");
//SendMessageW(hWnd, WM_SETTEXT, (WPARAM) 256,NULL);
while (GetMessage(&msg, NULL, 0, 0))
{
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
You do realize you have to create a window and then put the button inside the window?
Chances are the program is looking for a file in the wrong directory. Use full path names and do error checking to make sure the bitmap is loaded. Example:
HANDLE hImg = LoadImageW(NULL, L"c:\\fullpath\\Untitled.bmp", IMAGE_BITMAP, 0, 0,
LR_DEFAULTCOLOR | LR_DEFAULTSIZE | LR_LOADFROMFILE);
if (!hImg)
report error...
Don't put ShowWindow and UpdateWindow in the message loop. Just show the window and then call the message loop. Example:
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
For a class project I am creating a tic tac toe game with a GUI. The assignment requires the use of classes.
The assignment didn't originally require a GUI, so I created a working tic tac toe game with a command line interface. However, to earn some extra points I'd now like to implement a GUI. The problem is we haven't covered GUI design.
So far, I am able to display a window with 9 buttons on it. As you can see from the code below this is all done without classes. How could I separate my code into a single class or classes? Then, how would I display the GUI after creating an object in main?
I'm not trying to bring on any framework dependencies beyond the already-included windows.h system header.
In the end I'd like to have a class to handle the interface and a class to handle the logic.
Thanks for any suggestions
main.cpp
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow )
{
MSG msg ;
WNDCLASS wc = {0};
wc.lpszClassName = TEXT( "Buttons" );
wc.hInstance = hInstance ;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpfnWndProc = WndProc ;
wc.hCursor = LoadCursor(0, IDC_ARROW);
RegisterClass(&wc);
CreateWindow( wc.lpszClassName, TEXT("Buttons"),
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
150, 150, 340, 360, 0, 0, hInstance, 0);
while( GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch(msg)
{
case WM_CREATE:
{
CreateWindow(TEXT("button"), TEXT(""),
WS_VISIBLE | WS_CHILD ,
20, 20, 80, 80,
hwnd, (HMENU) 1, NULL, NULL);
CreateWindow(TEXT("button"), TEXT(""),
WS_VISIBLE | WS_CHILD ,
120, 20, 80, 80,
hwnd, (HMENU) 2, NULL, NULL);
CreateWindow(TEXT("button"), TEXT(""),
WS_VISIBLE | WS_CHILD ,
220, 20, 80, 80,
hwnd, (HMENU) 3, NULL, NULL);
CreateWindow(TEXT("button"), TEXT(""),
WS_VISIBLE | WS_CHILD ,
20, 120, 80, 80,
hwnd, (HMENU) 4, NULL, NULL);
CreateWindow(TEXT("button"), TEXT(""),
WS_VISIBLE | WS_CHILD ,
120, 120, 80, 80,
hwnd, (HMENU) 5, NULL, NULL);
CreateWindow(TEXT("button"), TEXT(""),
WS_VISIBLE | WS_CHILD ,
220, 120, 80, 80,
hwnd, (HMENU) 5, NULL, NULL);
CreateWindow(TEXT("button"), TEXT(""),
WS_VISIBLE | WS_CHILD ,
20, 220, 80, 80,
hwnd, (HMENU) 1, NULL, NULL);
CreateWindow(TEXT("button"), TEXT(""),
WS_VISIBLE | WS_CHILD ,
120, 220, 80, 80,
hwnd, (HMENU) 1, NULL, NULL);
CreateWindow(TEXT("button"), TEXT(""),
WS_VISIBLE | WS_CHILD ,
220, 220, 80, 80,
hwnd, (HMENU) 1, NULL, NULL);
break;
}
// incomplete
case WM_COMMAND:
{
if (LOWORD(wParam) == 1) {
Beep(40, 50);
}
if (LOWORD(wParam) == 2) {
PostQuitMessage(0);
}
break;
}
case WM_DESTROY:
{
PostQuitMessage(0);
break;
}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
You're probably looking for Raymond Chen's C++ version of his scratch program
It shows you how to use C++ classes (and member functions) together with the C-style callback approach used by the Windows API. Pretty much all his blog posts are worth reading, if you're interested in how to do things well in Windows, and why the APIs work the way they do.
But, there's still a lot that can be improved in Raymond's program, especially with the new std::unique_ptr (it didn't exist in 2005 when his post appeared, and he has a reputation for actually writing those over two years before they become public, so he may have not even had C++03 to work with).
Nonetheless, it shows you how to store a this pointer in a Win32 GUI object and how to dispatch messages to member functions for handling.
I'm trying to use the following code to show an empty border-less window, but no windows appear at all. I followed the documentation:
HWND hWnd = CreateWindowEx(WS_EX_TOPMOST,NULL,NULL,WS_POPUP,0,0,1000,1000,NULL,NULL,NULL,NULL);
ShowWindow(hWnd, SW_SHOW);
HWND hWnd = CreateWindowEx(WS_EX_TOPMOST, L"STATIC", NULL, WS_POPUPWINDOW, 0, 0, 100, 100, NULL, NULL, NULL, NULL);
ShowWindow(hWnd, SW_SHOW);