win32 window won't show child windows - c++

I'm trying to create a window with c++ winapi (CreateWindowExW, RegisterClassExW).
The window is dark, has the mica theme, and is borderless.
The window itself works fine, but when I'm trying to create any kind of child window (in this example, a button) it just won't show on the parent.
Does anyone why?
The window and button creation is as such:
WNDCLASSEXW wcx{};
wcx.cbSize = sizeof(wcx);
wcx.style = CS_HREDRAW | CS_VREDRAW;
wcx.hInstance = nullptr;
wcx.lpfnWndProc = wndproc;
wcx.lpszClassName = L"RunUIClass";
wcx.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
wcx.hCursor = ::LoadCursorW(nullptr, IDC_ARROW);
ATOM result = ::RegisterClassExW(&wcx);
auto handle = CreateWindowExW(
WS_EX_NOREDIRECTIONBITMAP | WS_EX_TOPMOST, L"RunUIClass", L"RunUI Window",
WS_POPUP | WS_THICKFRAME | WS_CAPTION | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX, GetSystemMetrics(SM_CXSCREEN) / 2 - (APP_WIDTH / 2), GetSystemMetrics(SM_CYSCREEN) / 2 - (APP_HEIGHT / 2),
APP_WIDTH, APP_HEIGHT, nullptr, nullptr, nullptr, userdata
);
auto button = CreateWindow(WC_BUTTON, L"Button",
WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
50, 50,
BUTTON_SIZE, BUTTON_SIZE,
handle, NULL, NULL, NULL);

Related

c++ WinAPI Layered Window, children do not paint

I am currently working on a project, where i need to create transparent bubble as main body. To make this transparence i used WS_EX_LAYERED on window creation. But now, i can't get children to render, but they do exist and even function like they should, they are just not visible. Without Layered Window mode everything renders just fine. What is wrong?
Here is my window creation:
winClass = {};
winClass.lpfnWndProc = WindowProc;
winClass.hInstance = hInstance;
winClass.hIcon = hIcon;
winClass.hCursor = LoadCursor(NULL, IDC_ARROW);
winClass.lpszClassName = CLASS_NAME;
winClass.hbrBackground = (HBRUSH)0;
winClass.lpszMenuName = NULL;
winClass.cbClsExtra = 0;
winClass.cbWndExtra = 0;
RegisterClass(&winClass);
Gdiplus::GdiplusStartupInput gdiinput = {};
gdiinput.GdiplusVersion = 1;
Gdiplus::GdiplusStartupOutput gdioutput = {};
Gdiplus::GdiplusStartup(&WinGDIToken, &gdiinput, &gdioutput);
hWnd = CreateWindowEx(
WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_LAYERED,
CLASS_NAME, // Window class
L"Color Picker", // Window text
WS_VISIBLE | WS_POPUP | WS_CLIPCHILDREN, // Window style
// Size and position
CW_USEDEFAULT, CW_USEDEFAULT, 700 * Scale, 516 * Scale,
NULL, // Parent window
NULL, // Menu
hInstance, // Instance handle
NULL // Additional application data
);
Window::PopulateClientWithWindows(hWnd);
And here is PopulateClientWithWindows(hwnd) func:
void Window::PopulateClientWithWindows(HWND hwnd)
{
HWND test = CreateWindow(L"edit", L"Test ", WS_VISIBLE | WS_CHILD , 50, 50,
100, 100, hwnd, NULL, hI, NULL);
}

DirectX window media keys not responding

Im making a game with a custom game engine and when you have selected the window that it creates it doesn't allow you to use media keys e.g. changing volume or playing/pausing music or anything that has to do with windows like getting the windows start menu and alt+tab behaves weird
It feels like my window is "blocking" all system specific keys and commands
The code is written in c++
Heres the code i'm using for creating the window:
bool FrameWork::CreateDXWnd(int x, int y, int width, int height)
{
HWND hwnd;
WNDCLASSEX wc;
m_hInstance = GetModuleHandle(nullptr);
//setup window class with default setings:
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = m_hInstance;
//wc.hIcon = LoadIcon(nullptr, IDI_WINLOGO);
wc.hIcon = (HICON)LoadImage(m_hInstance, ".\\Assets\\Icons\\NgineIcon512.ico", IMAGE_ICON, 32, 32, LR_LOADFROMFILE);
wc.hIconSm = wc.hIcon;
wc.hCursor = LoadCursor(nullptr, IDC_HAND);
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszMenuName = nullptr;
wc.lpszClassName = applicationName.c_str();
wc.cbSize = sizeof(WNDCLASSEX);
if (!RegisterClassEx(&wc))
{
Error(1);
return false;
}
//Style of window
//int nStyle = WS_OVERLAPPED | WS_SYSMENU | WS_VISIBLE | WS_CAPTION | WS_MINIMIZEBOX;
int nStyle = WS_OVERLAPPED | WS_SYSMENU | WS_VISIBLE | WS_CAPTION | WS_MINIMIZEBOX;
SettingsManager::GetInstance()->SetNativeResolution(GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
if (SettingsManager::GetInstance()->GetDisplayMode() == FULLSCREEN)
{
DEVMODE dmScreenSettings;
memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
dmScreenSettings.dmSize = sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = (unsigned long)SettingsManager::GetInstance()->GetScreenWidth();
dmScreenSettings.dmPelsHeight = (unsigned long)SettingsManager::GetInstance()->GetScreenHeight();
dmScreenSettings.dmBitsPerPel = 32;
dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);
}
else
{
}
if ((SettingsManager::GetInstance()->GetDisplayMode() == BORDERLESS))
{
hwnd = CreateWindowEx(WS_EX_APPWINDOW, applicationName.c_str(), applicationName.c_str(), WS_POPUP, x, y, SettingsManager::GetInstance()->GetScreenWidth(), SettingsManager::GetInstance()->GetScreenHeight(), nullptr, nullptr, m_hInstance, nullptr);
}
else
{
hwnd = CreateWindowEx(WS_EX_APPWINDOW, applicationName.c_str(), applicationName.c_str(), nStyle, x, y, SettingsManager::GetInstance()->GetScreenWidth(), SettingsManager::GetInstance()->GetScreenHeight(), nullptr, nullptr, m_hInstance, nullptr);
}
if (hwnd == nullptr)
{
Error(2);
Ngine::GetInstance()->Release();
PostQuitMessage(0);
return false;
}
if (!Ngine::GetInstance()->InitGraphics(hwnd))
{
Error(hwnd, 30);
Ngine::GetInstance()->Release();
PostQuitMessage(0);
UnregisterClass(applicationName.c_str(), m_hInstance);
m_hInstance = nullptr;
DestroyWindow(hwnd);
return false;
}
Ngine::GetInstance()->GetGraphics()->SetHwnd(hwnd);
ShowWindow(hwnd, SW_SHOW);
SetForegroundWindow(hwnd);
SetFocus(hwnd);
return true;
}
Tim. The code you are showing deals with creating a window, not with how to handle the input to the window. To handle input, you need to set up a Message handling loop in your code.
Typically, in a game engine, you will have a main loop or "Game Loop", with each pass through the loop typically resulting in a single frame drawn. The first thing the Game Loop does is handle window messages. This allows you to handle the typical windows functions. Then, once you have no more messages to deal with, you will move on to handling your game's logic and rendering.
I recommend you take a look at Braynzarsoft's tutorials. The tutorial I linked deals with setting up your window and how to make a bare-bones Windows Message system.
Once you understand the basics of that, you can refine your post if needed to get more information.

Dialog window reinitialisation issue

I have the following issue. In my c++ project I wanted to create a dialog window to input settings for the application to be used.
The window is created when you click in the menu: application -> robot settings.
I created the window in the following way:
void Robot_Settings::CreateSettingsWindow(HWND hWnd, RECT& windowSize)
{
GetWindowRect(hWnd, &windowSize);
HWND hSDlg = CreateWindowW(
L"SettingsDialogClass",
NULL,
WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_CLIPSIBLINGS,
(windowSize.right - SETTINGS_WINDOW_SIZE) / 2,
(windowSize.bottom - SETTINGS_WINDOW_SIZE) / 2,
SETTINGS_WINDOW_SIZE,
SETTINGS_WINDOW_SIZE,
hWnd,
NULL,
NULL,
NULL
);
}
then I have the window procedure:
LRESULT CALLBACK Robot_Settings::SettingsDialogProcedure(HWND hSDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_COMMAND:
switch (wParam)
{
case SETTINGS_BUTTON_SAVE:
collectInputs(hSDlg);
break;
case SETTINGS_BUTTON_CANCEL:
DestroyWindow(hSDlg);
break;
}
case WM_CREATE:
AddControlsToSettingsDialog(hSDlg);
break;
case WM_DESTROY:
DestroyWindow(hSDlg);
break;
default:
return DefWindowProcW(hSDlg, msg, wParam, lParam);
}
}
And I add the inner controls on WM_CREATE:
void Robot_Settings::AddControlsToSettingsDialog(HWND hSDlg)
{
// Create Text info about amount input
CreateWindowW(
L"Static",
L"Input the amount of robots you want to get simulated:",
WS_VISIBLE | WS_CHILD,
(int)(SETTINGS_WINDOW_SIZE * 0.15),
(int)(SETTINGS_WINDOW_SIZE * 0.2),
(int)(SETTINGS_WINDOW_SIZE / 2),
(int)(SETTINGS_WINDOW_SIZE / 2),
hSDlg,
NULL,
NULL,
NULL
);
// Create Text info about formation input
CreateWindowW(
L"Static",
L"Input the formation of th robots in this format -> \"x-x-x-x\" where x is the amount of robots you want to have in each row:",
WS_VISIBLE | WS_CHILD,
(int)(SETTINGS_WINDOW_SIZE * 0.15),
(int)(SETTINGS_WINDOW_SIZE * 0.4),
(int)(SETTINGS_WINDOW_SIZE / 2),
(int)(SETTINGS_WINDOW_SIZE / 2),
hSDlg,
NULL,
NULL,
NULL
);
// Create Text info about speed input
CreateWindowW(
L"Static",
L"Input the speed calculated in squares per second at which you want the robots to move:",
WS_VISIBLE | WS_CHILD,
(int)(SETTINGS_WINDOW_SIZE * 0.15),
(int)(SETTINGS_WINDOW_SIZE * 0.6),
(int)(SETTINGS_WINDOW_SIZE / 2),
(int)(SETTINGS_WINDOW_SIZE / 2),
hSDlg,
NULL,
NULL,
NULL
);
// Create TextField for amount input
hAmount = CreateWindowW(
L"Edit",
L"",
WS_VISIBLE | WS_CHILD | WS_BORDER | WS_TABSTOP,
(int)(SETTINGS_WINDOW_SIZE * 0.7),
(int)(SETTINGS_WINDOW_SIZE * 0.2),
100,
20,
hSDlg,
NULL,
NULL,
NULL
);
//formation radio buttons
CreateWindowW(
L"BUTTON",
L"Formation",
WS_VISIBLE | WS_CHILD | BS_GROUPBOX,
(int)(SETTINGS_WINDOW_SIZE * 0.7),
(int)(SETTINGS_WINDOW_SIZE * 0.35),
120,
120,
hSDlg,
NULL,
NULL,
NULL);
hTriangle = CreateWindowW(
L"BUTTON",
L"Triangle",
WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON | WS_TABSTOP,
(int)(SETTINGS_WINDOW_SIZE * 0.72),
(int)(SETTINGS_WINDOW_SIZE * 0.4),
100,
20,
hSDlg,
(HMENU) ID_RADIO_TRIANGLE,
NULL,
NULL);
hRectangle = CreateWindowW(
L"BUTTON",
L"Rectangle",
WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON | WS_TABSTOP,
(int)(SETTINGS_WINDOW_SIZE * 0.72),
(int)(SETTINGS_WINDOW_SIZE * 0.45),
100,
20,
hSDlg,
(HMENU) ID_RADIO_RECTANGLE,
NULL,
NULL);
hRhombus = CreateWindowW(
L"BUTTON",
L"Rhombus",
WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON | WS_TABSTOP,
(int)(SETTINGS_WINDOW_SIZE * 0.72),
(int)(SETTINGS_WINDOW_SIZE * 0.5),
100,
20,
hSDlg,
(HMENU) ID_RADIO_RHOMBUS,
NULL,
NULL);
// Create TextField for speed input
hSpeed = CreateWindowW(
L"Edit",
L"",
WS_VISIBLE | WS_CHILD | WS_BORDER | WS_TABSTOP,
(int)(SETTINGS_WINDOW_SIZE * 0.7),
(int)(SETTINGS_WINDOW_SIZE * 0.6),
100,
20,
hSDlg,
NULL,
NULL,
NULL
);
// Create button Cancel
CreateWindowW(
L"Button",
L"Cancel",
WS_VISIBLE | WS_CHILD | WS_BORDER | WS_TABSTOP,
(int)(SETTINGS_WINDOW_SIZE * 0.7),
(int)(SETTINGS_WINDOW_SIZE * 0.8),
100,
40,
hSDlg,
(HMENU)SETTINGS_BUTTON_CANCEL,
NULL,
NULL
);
// Create button Save
CreateWindowW(
L"Button",
L"Save",
WS_VISIBLE | WS_CHILD | WS_BORDER | WS_TABSTOP,
(int)(SETTINGS_WINDOW_SIZE * 0.7 - 110),
(int)(SETTINGS_WINDOW_SIZE * 0.8),
100,
40,
hSDlg,
(HMENU)SETTINGS_BUTTON_SAVE,
NULL,
NULL
);
}
So, my issue is, that every time I try to input any text or click on the radio buttons the window seems to be reinitialized or repainted (can't figure out which is happening but it's not a normal behaviour anyway). And if you check the rectangle radiobutton the window closes.
You can find the entire project at:
https://github.com/JamesHawkJ/cpp/tree/master/WycieczkaRobotow
Can you please help me solve this problem?
Every time you receive a WM_COMMAND message from any control other than SETTINGS_BUTTON_SAVE or SETTINGS_BUTTON_CANCEL, your window procedure falls through to WM_CREATE case and calls AddControlsToSettingsDialog. You are creating more and more child windows, stacked on top of each other.
Also, SettingsDialogProcedure is declared to return LRESULT, but it may reach the closing brace without encountering a return statement. This exhibits undefined behavior.

The Tab-key doesn't works in the child controls

The following is my winapi program that window contains 3 sets of controls:
The controls that created directly in the window
The controls in Group1
The controls in Group2
When I press Tab-key , it only traverse in set1.
Why I can't switch to the child control of the group1 and group2 by Tab-key?
#include <Windows.h>
LRESULT __stdcall WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message)
{
case WM_CTLCOLORSTATIC:
{
HDC hdcStatic = (HDC)wParam;
SetTextColor(hdcStatic, RGB(0, 0, 255));
SetBkMode(hdcStatic, TRANSPARENT);
return (LRESULT)GetStockObject(NULL_BRUSH);
}
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
////////////////////////////////////////////////////////////////////////////
void CreateEdit(const HWND &parent, const int &x, const int &y, const int &id) {
CreateWindow(L"EDIT", L"", WS_BORDER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, x, y, 200, 20, parent, (HMENU)id, NULL, NULL);
}
////////////////////////////////////////////////////////////////////////////
int __stdcall wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
{
WNDCLASSEX wndclass{};
wndclass.cbSize = sizeof(wndclass);
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.hInstance = hInstance;
wndclass.hbrBackground = CreateSolidBrush(RGB(255, 128, 255));
wndclass.lpszClassName = L"test";
RegisterClassEx(&wndclass);
HWND hWndMainWindow = CreateWindow(
wndclass.lpszClassName,
L"test",
WS_EX_OVERLAPPEDWINDOW | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE,
100, 100, 500, 500,
NULL, NULL, hInstance, NULL);
::ShowWindow(hWndMainWindow, SW_SHOW);
::UpdateWindow(hWndMainWindow);
//Creating Controls~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int x = 10, y = 20, id = 100;
HWND g1 = CreateWindow(L"button", L"Group1", WS_CHILD | WS_VISIBLE | BS_GROUPBOX | WS_TABSTOP | WS_GROUP, 0, 50, 220, 200, hWndMainWindow, (HMENU)++id, NULL, NULL);
//Controls in Group1
CreateEdit(g1, x, (y += 30), ++id);
CreateEdit(g1, x, (y += 30), ++id);
CreateEdit(g1, x, (y += 30), ++id);
CreateEdit(g1, x, (y += 30), ++id);
HWND g2 = CreateWindow(L"button", L"Group2", WS_CHILD | WS_VISIBLE | BS_GROUPBOX | WS_TABSTOP | WS_GROUP, 260, 50, 220, 200, hWndMainWindow, (HMENU)++id, NULL, NULL);
y = 20;
//Controls in Group2
CreateEdit(g2, x, (y += 30), ++id);
CreateEdit(g2, x, (y += 30), ++id);
CreateEdit(g2, x, (y += 30), ++id);
CreateEdit(g2, x, (y += 30), ++id);
//The controls that create directly in the main window
y = 270;
CreateWindow(L"static", L"Main Window Controls", WS_CHILD | WS_VISIBLE, x, y, 200, 30, hWndMainWindow, (HMENU)++id, NULL, NULL);
CreateEdit(hWndMainWindow, x, (y += 30), ++id);
CreateEdit(hWndMainWindow, x, (y += 30), ++id);
CreateEdit(hWndMainWindow, x, (y += 30), ++id);
CreateEdit(hWndMainWindow, x, (y += 30), ++id);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0) {
if (!IsDialogMessage(hWndMainWindow, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
The two child windows that host "Group1" and "Group2" both need to be marked as "control parents" with the WS_EX_CONTROLPARENT style. This style means:
The window itself contains child windows that should take part in
dialog box navigation. If this style is specified, the dialog manager
recurses into children of this window when performing navigation
operations such as handling the TAB key, an arrow key, or a keyboard
mnemonic
Change your code to create those windows as follows:
HWND g1 = CreateWindowEx(WS_EX_CONTROLPARENT, L"button", L"Group1", WS_CHILD | WS_VISIBLE | BS_GROUPBOX | WS_TABSTOP | WS_GROUP, 0, 50, 220, 200, hWndMainWindow, (HMENU)++id, NULL, NULL);
HWND g2 = CreateWindowEx(WS_EX_CONTROLPARENT, L"button", L"Group2", WS_CHILD | WS_VISIBLE | BS_GROUPBOX | WS_TABSTOP | WS_GROUP, 260, 50, 220, 200, hWndMainWindow, (HMENU)++id, NULL, NULL);
(As an aside, it seems wrong to make your windows children of the groupbox. They don't need to be - you can just position them inside it but make them siblings of it instead of children. The groupbox is specifically designed to work this way - I don't know how well it will work with the controls as children.)
Since you're not creating a dialog box, your main window should be created with the WS_EX_CONTROLPARENT style.
Make sure that you only place this style on your main window. The child windows should not be using this style.

Win 32 API, drawing two child windows with vertical splitter bar

Below is code, which I am using for creating child windows:
case WM_CREATE:
hInst = ((LPCREATESTRUCT) lParam) -> hInstance;
hWnd1 = CreateWindowEx( WS_EX_CLIENTEDGE | WS_EX_LEFT,
"edit", NULL,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | ES_MULTILINE | WS_VSCROLL,
0, 0, 0, 0,
hWnd, (HMENU) 1,
hInst, NULL );
hWnd2 = CreateWindowEx( WS_EX_CLIENTEDGE | WS_EX_LEFT,
"edit", NULL,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | ES_MULTILINE | WS_VSCROLL,
0, 0, 0, 0,
hWnd, (HMENU) 2,
hInst, NULL );
But this code produces horizontal splitter, and I want vertical splitter.
First I thought, if I change height and width parameters, I could create vertical splitter. But it was of no use.
For full code and sample example (in order to save space on SO):
http://old.sumitbirla.com/software/src/splitter.c
So, what is exactly keyword/parameter, which would produce vertical splitter bar.
The code you posted just creates two child windows. It has nothing to do with vertical or horizontal splitter. Handle the WM_SIZE message in the parent window to position and size the child windows for a vertical or horizontal split.