im using dev c++(no qt or visual studio) and have the following button code:
HWND hwndButton = CreateWindowEx(
WS_EX_CLIENTEDGE,
"BUTTON",
"Submit",
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
100,
45,
100,
40,
hWnd,
NULL,
(HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE),
NULL);
i am completely new to gui programming, and i wanted to have the window close when the button is clicked as a test for reading user input.
after reading online it looks like something that occurs within:
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY:
PostQuitMessage(EXIT_SUCCESS);
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
return FALSE;
}
and i have also seen people talk about "OnOk();" but i have no idea where i would put it. how would i have the window close if the button is clicked? where would i have the function to close it? where does the message even go that says the button was clicked? ive been searching for hours on the internet and have had no luck.
Related
I am working on Zoom SDK which is based on win32 gui.
I have created 3 buttons using CreateWindow method on the window handle, which is provided by the ZoomSDK.
Code + Screenshot - 1
Now there are two problems with this.
As soon as I click the buttons, they disappear.
See the Screen Shots BEFORE
See the Screen Shots AFTER
I want to know the reason why this is happening and how can I fix this?
HWND hFirstView, hSecondView;
cntrl->GetMeetingUIWnd(hFirstView, hSecondView);
cntrl->MoveFloatVideoWnd(100, 100);
HWND btnHwnd = CreateWindow(
TEXT("button"),
L"Open App",
WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
0, 0,
50, 25,
hFirstView,
(HMENU)100,
hInst,
NULL);
HWND btnHwnd2 = CreateWindow(
TEXT("button"),
L"Other",
WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
50, 0,
50, 25,
hFirstView,
(HMENU)101,
hInst,
NULL);
HWND btnHwnd3 = CreateWindow(
TEXT("button"),
L"Raise Hand",
WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
100, 0,
50, 25,
hFirstView,
(HMENU)103,
hInst,
NULL);
HDC hdc = GetDC(btnHwnd);
SetBkColor(hdc, GetSysColor(COLOR_BTNSHADOW));
SetTextColor(hdc, GetSysColor(COLOR_BACKGROUND));
ReleaseDC(btnHwnd, hdc);
int btnId = GetDlgCtrlID(btnHwnd);
//oldWndProc = (WNDPROC) GetWindowLong(hFirstView, GWL_WNDPROC);
oldWndProc = (WNDPROC) SetWindowLong(hFirstView,
GWL_WNDPROC, (LONG)WndProc);
SendMessage(btnHwnd, BM_SETSTATE, 1, 0);
SetWindowText(hFirstView, L"Title");
I want to handle click event for these buttons. I have tried to use SetWindowsLong to set another WndProc
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int id = GetWindowLong(hWnd, GWL_ID);
switch (message)
{
case WM_COMMAND: {
MessageBox(NULL, L"Sign of releaf!", L"Whoaa!", 0);
if (wParam == 1023) {
MessageBox(NULL, L"Sign of releaf!", L"Whoaa!", 0);
}
}
break;
}
return CallWindowProc(oldWndProc, hWnd, message, wParam, lParam);
}
Now, this WndProc gets called for other events such mouse move etc. It is not working for my three buttons. I want to handle click event i.e WM_COMMAND or any other technique possible.
Because I can not go inside the sdk (they don't provide sources, only .lib) so I can not change their WndProc, nor their internal WM_PAINT. The buttons are sort of overlay on top.
You should not be calling SetBkColor() and SetTextColor() from outside a WM_PAINT handler. The correct way to color a button is to either:
have the parent window handle the WM_CTLCOLORBTN notification.
The WM_CTLCOLORBTN message is sent to the parent window of a button before drawing the button. The parent window can change the button's text and background colors.
give the button the BS_OWNERDRAW style, and then have the parent window handle the WM_DRAWITEM notification.
Sent to the parent window of an owner-drawn button, combo box, list box, or menu when a visual aspect of the button, combo box, list box, or menu has changed.
Also, when a button sends a BN_CLICKED notification to its parent window, your subclass WndProc() doesn't need to use GetWindowLong(GWL_ID). First, you are calling it on the wrong HWND. And second, the button ID is carried in the message's wParam data.
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_COMMAND: {
if (HIWORD(wParam) == BN_CLICKED) {
switch (LOWORD(wParam)) {
case 100:
case 101:
case 103:
MessageBox(NULL, L"Sign of relief!", L"Whoaa!", 0);
break;
}
}
break;
}
}
return CallWindowProc(oldWndProc, hWnd, message, wParam, lParam);
}
I create the child hwnd as popup with close button and WndchildProc for handle message from child window
m_childHwnd = CreateWindowEx(
NULL,
TEXT("STATIC"), TEXT("childW"),
WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
m_parentHWnd, NULL,
GetModuleHandle(NULL), NULL
);
m_childhProc = (WNDPROC)SetWindowLongPtr(m_childHwnd , GWLP_WNDPROC, (LONG_PTR)WndChildProc);
static LRESULT CALLBACK WndChildProc(HWND hwnd, UINT message, WPARAM wParam,
LPARAM lParam)
{
switch (message)
{
case WM_CLOSE:
DestroyWindow(hwnd);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
default:
return CallWindowProc(m_childhProc, hwnd, message, wParam, lParam);
}
I expected when I press close button of child window the message WM_CLOSE will trigger. And I can close child hwnd with this way.
But when close button of child hwnd pressed, nothing happen. If close button of parent-hwnd pressed, WM_DESTROY message trigger.
So, I can't close (just) the child window with its close button.
How can I close a child window with its close button?
Updated: missing text in copying, added: CallWindowProc for default case.
I found solution with event WM_NCLBUTTONUP trigger when close button clicked.
case WM_NCLBUTTONUP:
ShowWindow(hwnd, SW_HIDE);
return 0;
I've a Button made using Win32Api that I want to be able to notify whenever the user put the mouse inside the button rectangle.
I noticed that when user does that the WM_NOTIFY is called but I don't know which flag to use for ensure that the user has the mouse inside it's area.
Here is my button:
HWND Button = CreateWindow("BUTTON", "Test",
WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON | BS_NOTIFY,
20, 240, 120, 20,
hwnd, (HMENU)101, NULL, NULL);
And my WndProc:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_NOTIFY:
{
//??? Here is where I want to do it
}
case WM_CREATE: //On Window Create
{
wHWND = hwnd;
if (onCreate != NULL)
onCreate(hwnd);
break;
}
case WM_COMMAND: //Command execution
{
//...
break;
}
case WM_DESTROY: //Form Destroyed
{
if (onDestroy != NULL)
onDestroy(hwnd);
PostQuitMessage(0);
break;
}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
I don't know if I'm in the right path using WM_NOTIFY or not, maybe there is an easier way to do that. Thank you!
Try catching the WM_SETFOCUS message instead if you want a generic way of tracking focus.
BN_SETFOCUS is sent as WM_COMMAND in the upper 16 bits of WPARAM (HIWORD):
The parent window of the button receives this notification code through the WM_COMMAND message
If you are not talking about focus but just the mouse position then you can use ChildWindowFromPointEx or RealChildWindowFromPoint and a timer.
I'm creating a win32 application in C++ and trying (unsuccessfully) to keep things somewhat object-orientated while still respecting the winapi message loop etc.
The problem I'm having is that my window seems to be drawing inconsistently and/or in a weird way that I have not encountered before. Eg:
This occurs when the window is resized. If I minimize the window and open it again, everything is black, apart from the buttons. Also, when moving my mouse from outside the window into the window, whatever my cursor was before getting inside the window is retained. For example, if there is a textbox behind the window, and I move my cursor from the textbox and into this window, the cursor remains the caret cursor.
I'm using this code to handle messages inside my WindowMain class:
std::map<HWND, WindowMain*> WindowMain::HWNDMap;
LRESULT CALLBACK WindowMain::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
if (HWNDMap.find(hWnd) == HWNDMap.end()) { return DefWindowProc(hWnd, msg, wParam, lParam); }
return HWNDMap[hWnd]->InstWndProc(hWnd, msg, wParam, lParam);
}
LRESULT CALLBACK WindowMain::InstWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_CLOSE:
PostQuitMessage(0);
break;
case WM_DESTROY:
DeleteObject(_hFont);
break;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
return 0;
}
The WindowMain::WndProc function is a static member of WindowMain. I use a std::map to map HWND to WindowMain* so that I can pass messages from the static method to the relevant WindowMain::InstWndProc. I feel like the problem might be here but I can't spot it.
In case it's relevant, this is the code I'm using to create the window:
WindowMain::WindowMain(HINSTANCE hInst) {
_isReady = false;
WNDCLASS wc;
memset(&wc, 0, sizeof(wc));
wc.lpfnWndProc = WndProc;
wc.lpszClassName = ClassName.c_str();
wc.hInstance = hInst;
wc.hbrBackground = (HBRUSH)(0);
if (!RegisterClass(&wc)) { return; }
_hWnd = CreateWindow(ClassName.c_str(), "AlchemyAC", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, NULL, NULL, hInst, NULL);
if (!_hWnd) { return; }
_hBtnStart = CreateWindow("BUTTON", "Start", WS_TABSTOP | WS_VISIBLE | WS_CHILD, 10, 10, 100, 24, _hWnd, NULL, hInst, NULL);
_hBtnStop = CreateWindow("BUTTON", "Stop", WS_TABSTOP | WS_VISIBLE | WS_CHILD, 10, 39, 100, 24, _hWnd, NULL, hInst, NULL);
if (!_hBtnStart || !_hBtnStop) { return; }
GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(LOGFONT), &_lf);
_hFont = CreateFont(_lf.lfHeight, _lf.lfWidth,
_lf.lfEscapement, _lf.lfOrientation, _lf.lfWeight,
_lf.lfItalic, _lf.lfUnderline, _lf.lfStrikeOut, _lf.lfCharSet,
_lf.lfOutPrecision, _lf.lfClipPrecision, _lf.lfQuality,
_lf.lfPitchAndFamily, _lf.lfFaceName);
SendMessage(_hBtnStart, WM_SETFONT, (WPARAM)_hFont, true);
SendMessage(_hBtnStop, WM_SETFONT, (WPARAM)_hFont, true);
EnableWindow(_hBtnStop, false);
HWNDMap[_hWnd] = this;
_isReady = true;
}
My question is, why is this strange painting issue occurring? I'm mainly interested in the odd thing that is happening with the cursor.
EDIT: I am using a while loop to translate and dispatch messages.
I'm trying to receive a message from a button when clicked.
But instead of receiving it from the main window, I would like to receive it from a tab control, which is a child of the main window. But I'm not sure how to go about this.
This is the creation of the button:
deAll = CreateWindowEx(0, "BUTTON", "Disable All", WS_CHILD | BS_PUSHBUTTON, 135, 49, 95, 26, tabs, (HMENU)204, instance, NULL);
Obviously, tabs is a tab control.
This is the creation of the tab control:
tabs = CreateWindowEx(0, WC_TABCONTROL, 0, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS, 0, 0, rc.right + 2, rc.bottom - 22, hwnd, NULL, instance, NULL);
And hwnd is the main window.
Any ideas? Or do I have to make every control a child of the main window?
This was made using the Win32 API in C++.
The tabs window is the parent window of the button, so the button will send a WM_COMMAND/BN_CLICKED notification to the tabs window when the button is clicked. You will have to subclass the tabs window via either SetWindowLongPtr(GWL_WNDPROC) or SetWindowSubClass() to receive that message. For example:
WNDPROC prevWndProc;
LRESULT CALLBACK myWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if ((uMsg == WM_COMMAND) && (HIWORD(wParam) == BN_CLICKED))
{
// LOWORD(wParam) is the ID, and lParam is the HWND,
// of the button that was clicked. do something ...
}
return CallWindowProc(prevWndProc, hWnd, uMsg, wParam, lParam);
}
tabs = CreateWindowEx(0, WC_TABCONTROL, 0, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS, 0, 0, rc.right + 2, rc.bottom - 22, hwnd, NULL, instance, NULL);
prevWndProc = (WNDPROC) SetWindowLongPtr(tabs, GWLP_WNDPROC, (LONG_PTR) &myWndProc);
Or:
LRESULT CALLBACK mySubClassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
if ((uMsg == WM_COMMAND) && (HIWORD(wParam) == BN_CLICKED))
{
// LOWORD(wParam) is the ID, and lParam is the HWND,
// of the button that was clicked. do something ...
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
tabs = CreateWindowEx(0, WC_TABCONTROL, 0, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS, 0, 0, rc.right + 2, rc.bottom - 22, hwnd, NULL, instance, NULL);
SetWindowSubclass(tabs, &mySubClassProc, 0, 0);
If a control is a child of a tab (or any other control) then it's the tab that will get notification messages like WM_COMMAND.
It's easiest to make your controls all children of your main window and just fix the z-order to make them appear in front of the tab (you already have WS_CLIPSIBLINGS set on the tab control, which you would also need). If you leave the controls as children of the tab then the only way to get notification messages is to sub-class the tab.
Or, you can do this the way property sheets do it, and use child dialogs (a dialog with the DS_CONTROL style set) to host the tab content. Then you can have a separate dialog procedure that handles messages from the child controls, and it makes it easy to show/hide a whole page of controls rather than handling them all individually. The TCM_ADJUSTRECT message can be used to calculate the size/position that you need to display your child dialog at.