I've created a formview using the Visual Studio resource editor but I can't get it to show.
The procedure to handle it's messages is this:
BOOL CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
switch (LOWORD (wParam))
{
case IDC_BUTTONCancel:
EndDialog(hDlg,0);
return TRUE;
}
break;
}
return FALSE;
}
When a button is pressed in the main window I call:
DialogBox(hInst, MAKEINTRESOURCE(IDD_FORMVIEW), hwnd, (DLGPROC)DlgProc);
The main window freezes, but there is no dialog shown.
I'd appreciate some help. Thanks in advance.
Related
I try to change standart WndProc function. I have this code:
HWND btn = CreateWindowEx(WS_EX_TRANSPARENT | WS_EX_CLIENTEDGE, L"BUTTON", L"Window title", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON
, 50, 50, 50, 50, (HWND)XApplicationMainWindow->window->_wnd, (HMENU)123,
(HINSTANCE)GetWindowLongPtr(XApplicationMainWindow->window->_wnd, GWLP_HINSTANCE), NULL);
SetWindowLongPtrW(btn, GWLP_WNDPROC, (LONG_PTR)SubclassWindowProc);
I can use L"BUTTON" class name, but when I change WndProc function I'll have a problem.
On this picture, you can see the blank square and normal button. If I try to create new WNDCLASS or WNDCLASSEX, I'll have nothing... Why?
How can I change the standart WndProc function, if I use L"BUTTON" class name?
It's my second WndProc:
LRESULT CALLBACK SubclassWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_CREATE:
break;
case WM_COMMAND:
//Event click
switch (LOWORD(wParam))
{
case 123:
OutputDebugStringA("Subclass click2");
break;
default:
break;
}
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
DefWindowProc() is the wrong window procedure for your SubclassWindowProc() to be calling.
You need to call the previous window procedure that you are replacing - the window procedure that handles all of the button's default behaviors (like drawing the button so it actually looks like a button, and responding to user input like a button, etc). SetWindowLongPtr() returns a pointer to that procedure to you, but you are currently ignoring it.
See Subclassing Controls on MSDN for more details.
Try this instead:
WNDPROC btnWndProc;
LRESULT CALLBACK SubclassWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_COMMAND:
//Event click
switch (LOWORD(wParam))
{
case 123:
OutputDebugStringA("Subclass click2");
break;
}
break;
}
return CallWindowProc(hWnd, btnWndProc, uMsg, wParam, lParam);
}
...
HWND btn = CreateWindowEx(...);
btnWndProc = (WNDPROC) SetWindowLongPtrW(btn, GWLP_WNDPROC, (LONG_PTR)SubclassWindowProc);
Alternatively, using SetWindowSubclass(), which is safer than using SetWindowsLongPtr(), eg:
LRESULT CALLBACK SubclassWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) {
switch (uMsg) {
case WM_NCDESTROY:
RemoveWindowSubclass(hWnd, SubclassWindowProc, uIdSubclass);
break;
case WM_COMMAND:
//Event click
switch (LOWORD(wParam))
{
case 123:
OutputDebugStringA("Subclass click2");
break;
}
break;
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
...
HWND btn = CreateWindowEx(...);
SetWindowSubclass(btn, SubclassWindowProc, 1, 0);
Now, that being said, your subclass will never call OutputDebugStringA(), because it will never receive the WM_COMMAND message you are expecting. When a button is clicked, a WM_COMMAND message is not sent to the button itself. The button posts a WM_COMMAND message to the button's parent window instead (in this case, to XApplicationMainWindow->window->_wnd). So, you need to handle the WM_COMMAND message in the window procedure of the parent window, not in the window procedure of the button itself.
Otherwise, if you still want to subclass the button itself, you will have to handle the WM_LBUTTON(DOWN|UP) and WM_KEY(DOWN|UP)/WM_CHAR messages that the button receives and then subsequently translates into a WM_COMMAND message for its parent window.
I've got a C++ project in which I'm using the Winapi to develop a window with a button and I want to change the text of the button when it's being hovered. For example, changing "Click me" to "Click me NOW!", when hovered. I've tried searching but I've not found any good ways to do this.
I noticed that when user hovers, the WM_NOTIFY message is received, but I don't know how to ensure that it has been called by the mouse hover. I've found that I can use TrackMouseEvent to detect hovering, but it's limited to a period of time and I want to execute an action every time the user hovers the button.
Here is how I create a button:
HWND Button = CreateWindow("BUTTON", "Click me",
WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON | BS_NOTIFY,
20, 240, 120, 20,
hwnd, (HMENU)101, NULL, NULL);
And this my window procedure:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_NOTIFY:
{
//??? Here is where I get a message everytime I hover the button, But I don't know any proper way to see if it has been executed by the button.
}
case WM_CREATE: //On Window Create
{
//...
}
case WM_COMMAND: //Command execution
{
//...
break;
}
case WM_DESTROY: //Form Destroyed
{
PostQuitMessage(0);
break;
}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
Assuming you're using the common controls there is the BCN_HOTITEMCHANGE notification code for the WM_NOTIFY message. The message includes the NMBCHOTITEM structure, which includes information for whether the mouse is entering or leaving the hover area.
Here's an example:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_NOTIFY:
{
LPNMHDR header = *reinterpret_cast<LPNMHDR>(lParam);
switch (header->code)
{
case BCN_HOTITEMCHANGE:
{
NMBCHOTITEM* hot_item = reinterpret_cast<NMBCHOTITEM*>(lParam);
// Handle to the button
HWND button_handle = header->hwndFrom;
// ID of the button, if you're using resources
UINT_PTR button_id = header->idFrom;
// You can check if the mouse is entering or leaving the hover area
bool entering = hot_item->dwFlags & HICF_ENTERING;
return 0;
}
}
return 0;
}
}
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
You can check the code of the WM_NOTIFY message to see if it is a NM_HOVER message.
switch(msg)
{
case WM_NOTIFY:
if(((LPNMHDR)lParam)->code == NM_HOVER)
{
// Process the hover message
}
else if (...) // any other WM_NOTIFY messages you care about
{}
}
You can use simply SFML to do this.
Code:
RectangleShape button;
button.setPosition(Vector2f(50, 50));
button.setSize(Vector2f(100, 40));
button.setFillColor(Color::Green);
if(button.getGlobalBounds().contains(static_cast<Vector2f>(Mouse::getPosition(/*your
window name*/window)
{
button.setFillColor(Color::Red);
}
I am trying to catch ENTER and ESC key press in singleline edit control.
When user presses ENTER or ESC I want to take away keyboard focus from edit control and set it to listview control. Listview control is edit control's sibling.
My goal is to write single subclass procedure that can be used for subclassing edit controls in both main window and dialog box.
I have found this MSDN article that I found useful because of its second solution. Below is my adaptation of the code.
// subclass procedure for edit control
LRESULT CALLBACK InPlaceEditControl_SubclassProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam,
UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
switch (message)
{
case WM_GETDLGCODE:
return (DLGC_WANTALLKEYS | DefSubclassProc(hwnd, message, wParam, lParam));
case WM_CHAR:
//Process this message to avoid message beeps.
switch (wParam)
{
case VK_RETURN:
// change focus to listview
SetFocus(hwndListView);
return 0L;
case VK_ESCAPE:
// change focus to listview
SetFocus(hwndListView);
return 0L;
default:
return ::DefSubclassProc(hwnd, message, wParam, lParam);
}
break;
case WM_KEYDOWN:
switch (wParam)
{
case VK_RETURN:
// change focus to listview
SetFocus(hwndListView);
return 0L;
case VK_ESCAPE:
// change focus to listview
SetFocus(hwndListView);
return 0L;
default:
return ::DefSubclassProc(hwnd, message, wParam, lParam);
}
break;
case WM_NCDESTROY:
::RemoveWindowSubclass(hwnd, InPlaceEditControl_SubclassProc, uIdSubclass);
return DefSubclassProc(hwnd, message, wParam, lParam);
}
return ::DefSubclassProc(hwnd, message, wParam, lParam);
}
QUESTION:
Is my adaptation correct or am I missing something (maybe instead of SetFocus I should use WM_NEXTDLGCTL like Raymond Chen pointed out)?
I am trying to Subclass the Listbox and the Edit Control of a Combobox for some customasing reasons. Below is the code work . Subclassing for Edit Control is working perfect but Listbox is not getting the messeage of MouseDown.
void Subclass(HWND hComboBox)
{
HWND hEdit=FindWindowEx(hComboBox, NULL, WC_EDIT, NULL);
HWND hCombo=FindWindowEx(hComboBox, NULL, WC_LISTBOX, NULL);
SetProp(hEdit, TEXT("Wprc"), (HANDLE)GetWindowLongPtr(hEdit, GWL_WNDPROC));
SubclassWindow(hEdit, ComboBox_Proc);
SetProp(hCombo, TEXT("Wprc1"), (HANDLE)GetWindowLongPtr(hCombo, GWL_WNDPROC));
SubclassWindow(hCombo, ComboBox_Proc1);
}
static LRESULT CALLBACK ComboBox_Proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CHAR:
break;
case WM_KEYDOWN:
break;
case WM_DESTROY:
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (DWORD)GetProp(hwnd, TEXT("Wprc")));
RemoveProp(hwnd, TEXT("Wprc"));
break;
default:
return CallWindowProc((WNDPROC)GetProp(hwnd, TEXT("Wprc")), hwnd, msg, wParam, lParam);
}
return FALSE;
}
static LRESULT CALLBACK ComboBox_Proc1(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_LBUTTONDOWN:
//PROBLEM IS HERE
break;
case WM_DESTROY:
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (DWORD)GetProp(hwnd, TEXT("Wprc1")));
RemoveProp(hwnd, TEXT("Wprc1"));
break;
default:
return CallWindowProc((WNDPROC)GetProp(hwnd, TEXT("Wprc1")), hwnd, msg, wParam, lParam);
}
return FALSE;
}
The ListBox part of a ComboBox is of type COMBOLBOX (with L).
The ComboLBox window is not a child of the ComboBox window.
The only way I found to subclass the COMBOLBOX control is as follows.
Windows sends the WM_CTLCOLORLISTBOX message to the COMBOBOX (no L) before the listbox is drawn. The lParam of this message contains the handle of the listbox.
case WM_CTLCOLORLISTBOX:
{
if ( !hSubclassedListBox )
{
hSubclassedListBox = (HWND)lParam;
SubclassWindow(hSubclassedListBox , MyLBProc);
}
}
Alsoo see this link for more information
For those who are using Visual Studio with WINVER set to 0500 or higher (Windows XP or later), you can use the GetComboBoxInfo function (passing the handle to the ComboBox), which will return (in a COMBOBOXINFO structure) the handles to both the Edit box and the ComboLBox (ListBox). The handles can then be used to get the CWnd-derived objects they represent.
Im sure this question is so easy for all you experts, but I am new to C++ and trying to add a comboBox to a "Option" Dialog in my program, I have done the following, but still can't see any item in Combo box can you please tell me what I am missing here.
in Resourse.h : #define IDD_TRIGGER_MODE 201
in Project.rc : COMBOBOX IDD_TRIGGER_MODE, 64,22,68,14,WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWN
any in the .cpp file I have the folliwng codes :
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_COMMAND:
///Other codes///
case IDM_OPTIONS:
g_hToolbar = CreateDialog(hInst, MAKEINTRESOURCE(IDD_OPTION_BOX), hWnd, ToolDlgProc);
if(g_hToolbar != NULL)
{
ShowWindow(g_hToolbar, SW_SHOW);
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
///Other codes///
}
the ToolDlgProc function :
INT_PTR CALLBACK ToolDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
HWND fgModes;
switch (message)
{
case WM_INITDIALOG:
fgModes = ::GetDlgItem(hDlg, IDD_TRIGGER_MODE);
fgModes = GetDlgItem(hDlg, IDD_TRIGGER_MODE);
if(fgModes!=NULL){
if(SendMessage(fgModes,CB_ADDSTRING,0, reinterpret_cast<LPARAM (_T("FreeRun")))==NULL){
return (INT_PTR)FALSE ;
}
return (INT_PTR)TRUE;
}
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
I appricate it for any idea to solve this problem, Thank you
thank you so much for your help. but I notice I didnt have problem in my code, simply the size of the ComboBox in .rc file was quite small (because of my lack of experiance in c++ API), so I change it to 42 now I can see my items. here is the edited code :
COMBOBOX IDD_TRIGGER_MODE, 64,22,69,42,WS_CHILD|WS_VISIBLE|CBS_DROPDOWNLIST
Change:
SendMessage(fgModes,CB_ADDSTRING,0, reinterpret_cast<LPARAM>("FreeRun"));
To:
SendMessage(fgModes,CB_ADDSTRING,0, reinterpret_cast<LPARAM>(_T("FreeRun")));
Also is there a good reason you are mixing CreateWindow/Ex and resources? I am assuming CreateWindow/Ex because I see you are using a WndProc for the first cpp, not a DialogProc.