I have a combo box and I need to intercept the changement of the selection while the user changes the selection by just hovering with the mouse without clicking. This is for displaying complementary information about the item the user is hovering over.
CBN_SELCHANGE won't do the job, because this message gets fired only when the user has actually changed the selection by clicking on one of the combo box items or when the up/down keys are pressed.
Apparently no message is fired while the user is just hovering over the the combobox.
Illustration
E.g: I need to know when the user moves the mouse from the entry 2 to the entry 33.
This is c++ subclass based on c# article which you mentioned:
LRESULT CALLBACK ComboProc(HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lParam, UINT_PTR uIdSubClass, DWORD_PTR)
{
if (msg == WM_CTLCOLORLISTBOX)
{
COMBOBOXINFO ci = { sizeof(COMBOBOXINFO) };
GetComboBoxInfo(hwnd, &ci);
if (HWND(lParam) == ci.hwndList)
{
int pos = SendMessage(ci.hwndList, LB_GETCURSEL, 0, 0);
OutputDebugStringA(std::to_string(pos).c_str());
OutputDebugStringA("\n");
}
}
if (msg == WM_NCDESTROY)
{
RemoveWindowSubclass(hwnd, ComboProc, uIdSubClass);
}
return DefSubclassProc(hwnd, msg, wParam, lParam);
}
...
SetWindowSubclass(hComboBox, ComboProc, 0, 0);
This was tested on Windows 10.
This can only report the hover selection in drop down list, it can't change the selection.
Related
I have a program that paints to the client area about 60hz using Direct3D 9, and the mouse is interfering, so I want to get rid of it only when it moves across the client area.
I thought that calling ShowCursor(false) in WM_MOUSEMOVE and calling ShowCursor(true) when WM_NCMOUSEMOVE is called by the system would work, but it results in a poor behavior.
So I found that TrackMouseEvent() would make the job, but I'm calling it in the following way:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static bool g_fMouseTracking = false;
switch (message)
{
case WM_MOUSEMOVE:
if (!g_fMouseTracking)
{
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(tme);
tme.dwFlags = TME_NONCLIENT;
tme.dwHoverTime = HOVER_DEFAULT;
tme.hwndTrack = hWnd;
g_fMouseTracking = TrackMouseEvent(&tme);
}
break;
case WM_NCMOUSEHOVER:
ShowCursor(true);
break;
...
and WM_NCMOUSEHOVER is never called. I don't know why.
Anyway, this is only one piece of code, to do what I want I know I need more code, but if it's not calling WM_NCMOUSEMOVE I can't start doing more advanced mouse hovering tricks.
When you want to track WM_NCMOUSEHOVER you must use TrackMouseEvent in WM_NCMOUSEMOVE.
I'm now trying to do some owner draw of the window frame , including the caption , the border , the mini/max/restore zone and the menubar. Escpecially for the menubar , I have done some gdi operations to redefine the area of the menubar , and repaint on WM_NCPAINT. However, when I press the Alt key or F10, the original menubar activated. I found it has something with the WM_SYSKEYDOWN , and then I blocked it. After that I put a control into the frame window, for expample, a edit control, when the control get focused, I press Alt or F10 , the original menubar of the frame window get activated again.
Wow , seems have something with the wm_notify message.
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_NCACTIVATE:
case WM_NCPAINT: {
//NC and Menubar redrawing.
BOOL active_flag;
HDC hdc;
RECT rect={0,0,0,0};
active_flag=(BOOL)wParam;
hdc=GetWindowDC(hwnd);
Frame_NCDraw(hwnd,hdc,rect,0,&active_flag);
Frame_MenuBarDraw(hwnd,hdc);
ReleaseDC(hwnd, hdc);
return !active_flag;
} break;
case WM_INITMENUPOPUP: {
//set the background of the menu item. a little long , no source code paste.
...
//
} break;
case WM_NCHITTEST: {
// redefine the area of the HTMENU.
} break;
case WM_MEASUREITEM: {
LPMEASUREITEMSTRUCT lpmis;
lpmis = (LPMEASUREITEMSTRUCT)lParam;
//Menu item adjust the height/width.
if(lpmis->CtlType == ODT_MENU) {
UINT menu_item_id = lpmis->itemID;
lpmis->itemWidth = 200;
lpmis->itemHeight = ((menu_item_id==0x0)?5:28);
}
} break;
case WM_DRAWITEM: {
UINT ctrl_id=(UINT)wParam;
LPDRAWITEMSTRUCT pDraw=(LPDRAWITEMSTRUCT)lParam;
if(pDraw->CtlType==ODT_MENU) {
Frame_DrawMenuItem(pDraw); // MenuItem owner drawing.
}
} break;
.....
}
So How should I deal with the activation of the original menubar ? I mean , I want to forbid the painting for the original menubar. Instead , I want my MenuBar activated by the Alt or F10 key press.
In addition to the WM_SYSKEYDOWN message, you will also receive WM_SYSCOMMAND with SC_KEYMENU, you need to handle this command to activate and display your own menu.
lParam contains the character code of the key that is used with the
ALT key to display the popup menu. For example , pressing ALT+F to
display the File popup will cause a WM_SYSCOMMAND with wParam equal
to SC_KEYMENU and lParam equal to'f'.
If only ALT/F10, the test result of lParam is 0.
case WM_SYSCOMMAND:
if (wParam == SC_KEYMENU)
{
//Draw activated menubar
switch (lParam)
{
case 0:
break;
case 'f':
//pop up menu "File"
break;
case 'h':
//pop up menu "Help"
break;
default:
break;
}
return 0;
}
else
return DefWindowProc(hwnd, msg, wParam, lParam);
Im trying to build simple application (Using Win32 API) which shows a black window within a button which should close the application, The problem is that I cant figure out how detect a PushBotton click.
Little peace of my code for example:
HWND hButton = CreateWindow(TEXT("Button"),TEXT("Exit"),WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,100,100,50,50,hWnd,0,hInstance,0);
Briefly, you need to give the button an ID and then handle WM_COMMAND messages from that button in your window proc. The article at http://www.infernodevelopment.com/c-win32-api-tutorial gives a decent example.
You need to analyze WM_COMMAND
message in main window procedure:
LRESULT CALLBACK MainWndProc(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam) // second message parameter
{
if ((uMsg == WM_COMMAND) && ((HWND)lParam == hButton)) //check MSDN for WM_COMMAND and BN_CLICKED notifications
{
//button was pressed
}
.......
}
Lets say I have a window with 2 dialogs, each having its own set of controls/information.
One is displayed on the window and the other is hidden, and I have a button switching between them.
How would I animate the transition between the 2 dialogs, like having it slide back and forth?
Note: I'm trying to use only the windows api for this.
Hans is correct, you can use the Windows API AnimateWindow.
AnimateWindow Function
here an example:
int CALLBACK EventDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
AnimateWindow(hwndDlg, 100, AW_SLIDE | AW_HOR_POSITIVE);
return 1;
}
case WM_PAINT:
{
return 1;
}
}
return 0;
}
I'm trying to set the text on the "save" button of the Windows "Save file as..." dialog.
I've set up the hook, received the message, found the button (nb. If I call "GetWindowText()" I see "&Save" so I know it's the right button).
Next I changed the text using "SetWindowText()" (and called "GetWindowText()" to check it - the text is correct).
But ... the button still says "Save".
I can change the "Cancel" button using the exact same code - no problem. What's so special about the "Save" button? How can I change it.
Code (for what it's worth):
static UINT_PTR CALLBACK myHook(HWND hwnd, UINT msg, WPARAM, LPARAM)
{
if (msg == WM_INITDIALOG) {
wchar_t temp[100];
HWND h = GetDlgItem(GetParent(hwnd),IDOK);
GetWindowTextW(h,temp,100); // temp=="&Save"
SetWindowTextW(h,L"Testing");
GetWindowTextW(h,temp,100); // temp=="Testing"
}
}
I finally made it work....
I'm pretty sure there's something funny going on with the "Save" button but this code will wrestle it into submission:
// I replace the dialog's WindowProc with this
static WNDPROC oldProc = NULL;
static BOOL CALLBACK buttonSetter(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// Set the button text on every window redraw....
if (msg == WM_ERASEBKGND) {
SetDlgItemTextW(hwnd,IDOK,L"OK");
}
return oldProc(hwnd, msg, wParam, lParam);
};
// This is the callback for the GetWriteName hook
static UINT_PTR CALLBACK GWNcallback(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HWND dlg = GetParent(hwnd);
if (msg == WM_INITDIALOG) {
oldProc = (WNDPROC)GetWindowLongPtr(dlg, GWL_WNDPROC);
if (oldProc !=0) {
SetWindowLongPtr(dlg, GWL_WNDPROC, (LONG)buttonSetter);
}
}
// We need extra redraws to make our text appear...
InvalidateRect(dlg,0,1);
}
You probably need to redraw the window after setting the text.
Try calling UpdateWindow() after setting the text.
Use CDM_SETCONTROLTEXT message to set the text rather than mess with SetWindowText directly, i.e.
SendMessage(hwnd, CDM_SETCONTROLTEXT, IDOK, L"Testing");
http://msdn.microsoft.com/en-us/library/ms646960(VS.85).aspx has more on customizing open/save dialogs