Environment: Visual Studio 2008, Visual Studio Feature Pack, MFC Dialog App, Windows XP, New Common Controls.
I'm having a problem with a list control that happens to be on a tab control.
To reproduce the problem simply create a dialog based app. Place a tab control on that dialog, then put a list control onto that tab control. You don't need to add any code to the project. Just build and run. Set the focus to the list view and then either minimize the dialog or bring another window in front of it.
Now bring the dialog back to the foreground, the list will not draw itself correctly.
One thing I have tried is handle the set focus event for the list control, but left it with an empty method body, ie...
void CMyListControl::OnSetFocus(CWnd* window)
{
// Default();
}
Then the redraw problem goes away, however now you can not select items within the list. Uncommenting the call to Default makes the problem come back.
If I move the list off of the tab the problem goes away. If I set the focus to another control on the tab or dialog, the problem goes away. This is a weird one.
In fact, if you watch closely you can see the list drawing itself and then being obscured by the tab control.
I know it's late but I had them same problem today. You need to set ListView's parent to Tab control.
hWndTab = CreateWindowEx(WS_EX_CLIENTEDGE, WC_TABCONTROL, NULL,
WS_CHILD | WS_TABSTOP | WS_VISIBLE,
0, 0, 0, 0, hWnd, (HMENU) IDC_TAB, hInstance, NULL);
hWndList = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, NULL,
WS_CHILD | WS_TABSTOP | WS_VISIBLE | LVS_REPORT,
0, 0, 0, 0, hWndTab, (HMENU) IDC_LIST, hInstance, NULL);
Note parent window handler for hWndList: hWndTab. Or you can use SetParent.
Related
I have a Direct2D program, and my goal is to have a Win32 button rendered with the Direct2D window.
I was able to compile the program fine, but the problem is that the button only shows when I click on it. Once I click outside of the button, it just goes invisible. It's even invisible when I open the application. What I expect is for the button to be visible all the time. I'm not necessarily worried about if it renders above or below the Direct2D renderer.
When I click on it:
When I click outside the button (just blank):
Here is my render function:
create_drs(); // Creates device resources
m_pRenderTarget->BeginDraw();
m_pRenderTarget->Clear(D2D1::ColorF(bg.r / 255, bg.g / 255, bg.b / 255, 1));
HWND hwndButton = CreateWindow(
L"BUTTON",
L"a button",
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
0,
0,
150,
150,
m_hwnd,
NULL,
(HINSTANCE)GetWindowLongPtr(m_hwnd, GWLP_HINSTANCE),
NULL);
m_pRenderTarget->EndDraw();
I've tried taking out the Clear function, but it's still invisible when the application opens, but stays visible forever once I click on it. I also tried looking online, but couldn't find a sufficient solution for this specific problem.
I have designed activeX control which consist of one editbox and one combobox.
I am trying to place the editbox over combobox so that whenever the user select any item from the combobox it should sit to the editbox. So my editbox should coveringup combobox'edit portion and only the arrow button is visible for the combobox.
Isuue: Whenever I am trying to move my mouse cursor over that control the combobox is coming front of editbox.I have made the design such as editbox is just covering up the combobox but only when the focus goes back to combobox and that is taking the combobox front.
Tried Approaches: In one of the my defined function I tried all the below function to make edit box over the combobox.
1)BringWindowToTop
2)SetForegroundWindow
3)SetWindowPos
My code for that Function:
void DetermineWindowsShown()
{
m_edit.EnableWindow(m_bEnabled);
m_combo.EnableWindow(m_bEnabled);
//here only I tried all the diff function
m_edit.BringWindowToTop();
//m_edit.SetForegroundWindow();
//m_combo.SetWindowPos(&CWnd::wndBottom ,0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}.
I am calling DetermineWindowsShown many places so that always editbox is above the combobox.
BringWindowToTop is usually for MDI windows. SetForegroundWindow is for main window.
You should be able to use SetWindowPos, apply it to both, not just one:
m_combo.SetWindowPos(&CWnd::wndBottom, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
m_edit.SetWindowPos(&CWnd::wndTop, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
In WINAPI, I create a button like:
case WM_CREATE:
{
Start = CreateWindowEx(WS_EX_TRANSPARENT, "Button", "Start", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 20, 50, 75, 25, window, (HMENU)ID_START, hInstance, NULL);
break;
}
The button looks like:
But I need it to look like this one (which I did in .Net):
How can I get rid of that black border/background?
Start = CreateWindowEx(WS_EX_TRANSPARENT, ...);
You got the black outline because you used the WS_EX_TRANSPARENT style flag. It isn't clear why you used it, there's not much you can do with it when you use the Button control. It is otherwise probably the least understood style flag. Pass 0 instead to get a normal looking button.
It is otherwise a lost cause to get the exact look of a .NET button, Winforms doesn't use the built-in Button control. It creates its own, using a custom renderer to get the gradient look. Reproducing that native code is a lot of work.
I think the border you are seeing is because the button has the "Default Button" property. If you turn that off, then it will have a normal border. The Default property just tells Win32 which button to activate if the users hits ENTER on the dialog/form. If you only have one button, then it will always have the default property. If you add a second, it will not.
The property is the BS_DEFPUSHBUTTON property, so in your CreateWindowEx call, you should be able to do something like:
Start = CreateWindowEx(WS_EX_TRANSPARENT, "Button", "Start", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | ~BS_DEFPUSHBUTTON, 20, 50, 75, 25, window, (HMENU)ID_START, hInstance, NULL);
If not, you'll have to set it with ModifyStyle or ModifyStyleEx, and pass it in the "Remove" parameter. I forget which one the specific styles have to be passed in, but if I recall correctly, it's the normal style params, NOT the EX params.
I haven't tested this, but try creating the button like this:
Start = CreateWindowEx(0, WC_BUTTON, "Start", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_TEXT, 20, 50, 75, 25, window, (HMENU)ID_START, hInstance, NULL);
break;
It also might depend on how you've created your main window. Can you post the code for your main window creation?
EDIT: I mis-identified the border as the default-button border. As David Hefferman pointed out, it's not. That is, I have now reproduced that border effect; when the program starts there is no border, but just a little mousing over the left button creates the border – at least in Windows 7.
Original answer follows:
The black border is because it's default. You shouldn't interfere with the system's visualization of default buttons etc. Users rely on those cues.
To change the font, maybe, like, WM_SETFONT?
Disclaimer: I haven't tried that. It might be you need to handle WM_CTRLCOLOR or something like that. Just try it out, and in the end, if the default buttons don't cut it for you, simply implement your own button.
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;