I have main window which contains child. In child I need to handle mouse wheel scroll, however it doesn't matter where I scroll mouse wheel message goes to main window. I got those results with Spy++.
Don't know why it happens, but I think that something is wrong with child creation, my code:
m_window = CreateWindowEx(0, CustomTreeView::m_className.c_str(), NULL, WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL, x, y, width, height, parent, NULL, NULL, NULL);
The WM_MOUSEWHEEL message is sent to the window with focus (i.e. the last one to have SetFocus() called on it). It doesn't matter where the mouse cursor is located - the messages will always go to the focus window.
If the focus window doesn't handle the wheel message, it is propogated by DefWindowProc to the focus window's parent, and again to its parent, and so on. So wheel messages only move up the window hierarchy.
If you want a child window that doesn't have input focus to get wheel messages then you need to arrange to forward them to it yourself.
If you do this, you should do it via a different message, to avoid the possibility of infinite loops.
Related
I'm supporting an older Win32 app that's running DirectX 9, although it's using the Win32 API to handle mouse and keyboard input.
Alt-tabbing away and back works fine while windowed, but if I got full screen and then alt-tab away, the app no longer receives mouse events in its WndPrc function. I'm just doing a borderless full screen window for the change.
Furthermore, when I mouse over the full screen application, I'm receiving cursor changes based on apps behind the app, and when I click, the app disappears and reappears and the mouse events interact with those apps in the back.
The default window style:
WS_POPUP | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX;
The code for going full screen:
SetWindowLong(hWnd, GWL_STYLE, WS_VISIBLE | WS_POPUP);
SetWindowPos(hWnd, HWND_TOP, 0, 0, monitor_width, monitor_height, SWP_FRAMECHANGED);
The messages I receive when I click anywhere over the application (I don't receive any mouse move or mouse hover events):
WM_WINDOWPOSCHANGING
WM_WINDOWPOSCHANGED
WM_NCACTIVATE
WM_GETTEXT
WM_ACTIVATE
WM_NCACTIVATE
WM_GETTEXT
WM_ACTIVATE
WM_ACTIVATEAPP
I was suspicious of the position changing events and checked, but the flags SWP_NOSIZE and SWP_NOMOVE were set. Basically, after I receive my last WM_MOUSELEAVE before alt-tabbing or clicking in another application window, that's it when it comes to mouse events.
If I don't leave my application, mouse events continue to work fine in full screen.
How would I go about deselecting the text in edit control?
After entering the input I want the user to be able to deselect the edit control.
Because even after you click out of it and press a key, it gets entered into the edit.
Here is the code for my edit control:
HFONT fontMain = CreateFont(
-16, // Height Of Font
0, // Width Of Font
0, // Angle Of Escapement
0, // Orientation Angle
0, // Font Weight
false, // Italic
false, // Underline
false, // Strikeout
ANSI_CHARSET, // Character Set Identifier
OUT_TT_PRECIS, // Output Precision
CLIP_DEFAULT_PRECIS, // Clipping Precision
ANTIALIASED_QUALITY, // Output Quality
FF_DONTCARE|DEFAULT_PITCH, // Family And Pitch
TEXT("Calibri"));
HWND editControl = CreateWindow(
TEXT("EDIT"),
TEXT("TEST TEXT"),
WS_CHILD | WS_VISIBLE | ES_LEFT | ES_MULTILINE,
x, y, width, height,
window,
(HMENU) 100,
instance,
NULL);
SendMessage(window /* parent window */, WM_SETFONT, (WPARAM)fontMain, NULL);
DeleteObject(fontMain);
I have checked MSDN docs and have not found any additional styles to add to achieve the task.
If you have any ideas on how to achieve this task could you help me out?
Thank you.
You could use the same trick that works to dismiss dropdown list (of combo box), popup menus, and the like.
You'll need to subclass the EDIT control so you receive messages first to your own window procedure.
In your textbox subclass WM_SETFOCUS handler, call SetCapture so the next click is delivered to the textbox even if it's outside.
In the textbox subclasses's handler for mouse click messages, test the location and if outside the textbox, call SetFocus(NULL) to give up the focus. (This is where a popup would dismiss itself). Also call ReleaseCapture().
Also call ReleaseCapture() in the subclass's WM_KILLFOCUS handler, since mouse clicks are not the only way to lose focus.
The above is the way to have any click outside the textbox remove its focus. If you only want clicks in the client area of your parent window to defocus the textbox, then you can certainly skip the subclassing and capture, and just handle the mouse click events in the parent window, calling SetFocus(NULL) or SetFocus(parentHWnd).
I handled the WM_LBUTTONDOWN message in the window proc.
Such that when I click the mouse button on the parent window, it will set the focus to the parent window.
static LRESULT WINAPI WndProc
(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message){
case WM_LBUTTONDOWN : {
// Passing the parent window as the parameter.
SetFocus(HWND parentWindow);
}
}
}
This method works as the WM_LBUTTONDOWN might not be triggered if you click on any other window except the parent window.
There might be some exceptions to the above statement, but overall it works with buttons and edits but not static text for some reason.
The answers were provided by:
#PaulSanders and #BenVoigt
In using layered windows in win32 or atl/wtl c++ if I set the main window's alpha to 0 and paint on the child, fake window so that it is viewable and click the window, the entire window is a click through.
I want to be able to make only regions of the window click through, not the entire window, let's say if I want to paint a rounded corner window, I make the bottom/main window to be click through but I don't want the upper "fake" window to be click through, i want to be able to click on it. How do I do that?
Where I am so far:
In the OnInitDialog function of the main window :
::SetWindowLong( m_hWnd, GWL_EXSTYLE, ::GetWindowLong(m_hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);
BYTE bTran = 0;
::SetLayeredWindowAttributes( m_hWnd, 0, bTran, LWA_ALPHA);
and when I create the fake window:
m_hFakeWnd = ::CreateWindowEx( WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_NOACTIVATE | WS_EX_LEFT
, m_strWndClassName
, NULL
, WS_VISIBLE | WS_OVERLAPPED
, rc.left
, rc.top
, rc.Width()
, rc.Height()
, GetSafeHwnd()
, NULL
, ::GetModuleHandle(NULL)
, NULL
);
IF, I set eliminate the WS_EX_TRANSPARENT flag the fake window is click-able while the main is click through, but! it doesn't respond to anything! click/drag. none.
It sounds like you are covering another window solely for the purpose of intercepting clicks?
Anyway, you need to handle window's WM_NCHITTEST message in order to be able to let system know that particular position is transparent, in which case you return HTTRANSPARENT:
In a window currently covered by another window in the same thread (the message will be sent to underlying windows in the same thread until one of them returns a code that is not HTTRANSPARENT).
Use alpha 1 instead of 0 in the regions you want to accept clicks. The window will still be completely invisible but the areas of alpha 1 will register clicks and mouse movements as normal.
Note that to get per-pixel alpha you'll need to use UpdateLayeredWindow rather than SetLayeredWindowAttributes.
Make two windows, one with click-through properties and another with normal ones.
I tried to create a child window using:
CreateWindowEx( NULL, NULL, "MyChild", WS_CHILD | WS_VISIBLE | WS_BORDER, 300, 300, 400, 200, hParentWnd, NULL, NULL );
where the parent HWND hParentWnd has many other child windows already. However, this created a child window hiding behind all the siblings. Windows Spy++ shows that it is on top (first) of the z-order among the child windows of hParentWnd. I have tried all different win32 commands including SetWindowPos(), BringWindowToTop(), SetForegroundWindow(), SetFocus(), SetActiveWindow(), SendMessage(WM_ACTIVATE, 0, 0), etc., but none brings it from behind the siblings. When I replaced WS_CHILD by WS_OVERLAPPEDWINDOW in the CreateWindowEx() command, the created non-child window has no problem showing as the topmost foreground active window. So what must I do to get the child window to the top from behind the siblings?
Thanks a million.
z/0
It is quite explicit in the MSDN article for CreateWindowEx():
If the created window is a child window, its default position is at the bottom of the Z-order. If the created window is a top-level window, its default position is at the top of the Z-order.
You'll need to move it to the top of the Z-order with SetWindowPos().
I have a Windows program which has two 2 windows in it:
hwnd (main interface)
hwnd2 (toplevel window, no parent, created by hwnd)
When I double click on hwnd, I need hwnd2 to pop up and show some data, so I use this function to bring hwnd2 to top:
BringWindowToTop(hwnd2);
hwnd2 is brought to top, but there is one thing odd. When I click on hwnd2 again, hwnd (main interface) pops itself up again automatically.
I tried to use the following function to solve this problem, but non of them works.
SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
//doesn't work
BringWindowToTop(hwnd2); //This is the function brings hwnd2 to top
SetForegroundWindow(hwnd2); //doesn't work
SetWindowPos(hwnd2, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
//doesn't work
SetWindowPos(hwnd2, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
// hwnd2 "always" on top, not what I want
SetActiveWindow(hwnd2); // doesn't work too (for replying to Magnus Skog, thanks)
SwitchToThisWindow(hwnd2, TRUE);// got the same problem with BringWindowToTop function
SwitchToThisWindow(hwnd2, FALSE);
How could I solve this problem?
Thanks in advance.
(for replying to aJ, hwnd2 doesn't have parent because it needs to be a toplevel window so it can be in front/back of other windows)
(hwnd2 is a media player which is composed of several windows, one of the windows is for video dispaly, two other trackbar controls for progress bar and volume bar, one Toolbar control for control panel.)
(There is one this might help, no matter which window I click on hwnd2, hwnd pops up automatically as loong as "the mouse is on top of hwnd in Z-order", including menu bar and non-client area, etc.)
(This media player is writen in Direct Show. I use IVideoWindow::put_Owner to put video window as the video owner, Direct Show internally creates a sub-video window as a child of the video window. Except for this sub-video window which I can't see the source code, I don't see any thing suspicious in hwnd2.)
I found the reason, which is because of Direct Show. I use multithread to execute it, and then the problem's solved. But...why??
This problem can be resolved by using PostMessage (rather than SendMessage).
try this,it is said coming from M$
HWND hCurWnd = ::GetForegroundWindow();
DWORD dwMyID = ::GetCurrentThreadId();
DWORD dwCurID = ::GetWindowThreadProcessId(hCurWnd, NULL);
::AttachThreadInput(dwCurID, dwMyID, TRUE);
::SetWindowPos(m_hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
::SetWindowPos(m_hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE);
::SetForegroundWindow(m_hWnd);
::SetFocus(m_hWnd);
::SetActiveWindow(m_hWnd);
::AttachThreadInput(dwCurID, dwMyID, FALSE);
In order to bring a window to top, you should get your window handle,thread handle, the windows thread handle who is in foreground
then we attach our thread to foreground window thread and get input by AttachThreadInput, then we set our window z order
to topmost and then restore its z order to normal, call SetForegroundWindow,SetFocus,SetActiveWindow to make sure our window is brought to top and is active and have focus
then deattach the input queue from the old foreground window thread, make our thread the only one who capture the input events
So why should We call AttachThreadInput, it is because
SetFocus sets the keyboard focus to the specified window. The window must be
attached to the calling thread's message queue.
What does AttachThreadInput do?
The AttachThreadInput function can be used to allow a set of threads
to share the same input state. By sharing input state, the threads
share their concept of the active window. By doing this, one thread
can always activate another thread's window. This function is also
useful for sharing focus state, mouse capture state, keyboard state,
and window Z-order state among windows created by different threads
whose input state is shared.
We use SetWindowPos to bring the windows to topmost and show the window if the window is hidding by using SWP_HIDEWINDOW
SetWindowPos function changes the size, position, and Z order of a
child, pop-up, or top-level window. These windows are ordered
according to their appearance on the screen. The topmost window
receives the highest rank and is the first window in the Z order
If your problem is your window is also minimized , you should add one line code to the end
ShowWindow(m_hWnd, SW_RESTORE);
Both work great:
::SetForegroundWindow(wnd)
or
::SetWindowPos(m_hWnd, // handle to window
HWND_TOPMOST, // placement-order handle
0, // horizontal position
0, // vertical position
0, // width
0, // height
SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE// window-positioning options
);
But remember that the last one sets the window always on top.
After many tries and errors.I found following solution to this problem:
SendMessage(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0); // restore the minimize window
SetForegroundWindow(hwnd);
SetActiveWindow(hwnd);
SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
//redraw to prevent the window blank.
RedrawWindow(hwnd, NULL, 0, RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN );
The hwnd is your windows HWND . Please do not just copy and paste. You also need use GetLastError to check api error after every api call.
I have confirm following result on my win7:
Can restore minimize window and no error return.
If the window already top, the window title will blink and no error return.
If the window has closed, it will return the error "0x578 Invalid window handle."
It can bring the window to the top on all not top-most window and no error return.(For example it will behind the top-most taskmanager)
It do not make the window top-most. The user can make other window on top of it.
SwitchToThisWindow works best for me.
Have you tried SetActiveWindow()?
This will restore an app if minimized and bring it to the front:
ShowWindow(hWnd, SW_SHOW);
SetForegroundWindow(hWnd);
//work great!
Var
WndHandle:HWND;
begin
WndHandle :=FindWindowEx(0,0,nil,'Calculator');
PostMessage(WndHandle,WM_SHOWWINDOW,SW_RESTORE,0);
SetForegroundWindow(WndHandle);
end;