I'm having troubles showing my tray menu above the taskbar. It doesn't matter what I specify as y-position, it only gets against the taskbar at best. The tray menu is a resource.
This is the code I'm using for a rightclick on the systrayicon:
// The message loop
case WM_RBUTTONUP:
{
CPoint point;
::GetCursorPos(&point);
CMenu menu;
menu.LoadMenu(IDR_MENU1);
HMENU hMenu = menu.GetSubMenu(0)->Detach();
CMFCPopupMenu* pMenu = theApp.GetContextMenuManager()->ShowPopupMenu(hMenu, point.x-5, point.y, this, TRUE);
pMenu->SetForegroundWindow();
break;
}
Indeed RecalcLayout makes sure that a popup is displayed within monitor's working area (not obscuring taskbar.
But there is nothing to prevent you to override this behavior.
The difference between a Windows’ menu and CMFCPopupMenu is that the menu is a window that is created by the OS and CMFCPopupMenu is a frame window that mimics the behavior of the menu.
You were almost there but you missed the fact that SetForegroundWindow does not move window, it merely changes Z-order.
I personally do not see any advantage of doing it. However, as I say nothing is impossible to achieve.
Do following if you really want to do it against advice:
CMFCPopupMenu* pMFCMenu = pCntxtMgr->ShowPopupMenu(hMenu, ptClick.x, ptClick.y, AfxGetMainWnd());
CRect rectMenu;
pMFCMenu->GetWindowRect(rectMenu);
pMFCMenu->SetWindowPos(&CWnd::wndTopMost, rectMenu.left, rectMenu.top + 25, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
25 is just an arbitrary number I used for demo purpose. You will have to calculate it to prevent menu bottom appearing off the screen.
Related
I have created a listbox similar to the code provided here. In my UI, will the tab focus rect be automatically drawn by DefWindowProc() or do I need to take care of that ? I don't see the focus rect being drawn on tab focus.
Thanks.
HWND CreateListView (HWND hwndParent)
{
INITCOMMONCONTROLSEX icex; // Structure for control initialization.
icex.dwICC = ICC_LISTVIEW_CLASSES;
InitCommonControlsEx(&icex);
RECT rcClient; // The parent window's client area.
GetClientRect (hwndParent, &rcClient);
// Create the list-view window in report view with label editing enabled.
HWND hWndListView = CreateWindow(WC_LISTVIEW,
L"",
WS_CHILD | WS_VISIBLE | LVS_LIST,
0, 0,
rcClient.right - rcClient.left,
rcClient.bottom - rcClient.top,
hwndParent,
(HMENU)IDM_CODE_SAMPLES,
g_hInst,
NULL);
return (hWndListView);
}
Normally,the default window procedure draws a focus rectangle for the list box item drawn by the owner in response to the WM_DRAWITEM message.
In MSDN
For an empty list box or combo box, itemID can be -1. This allows
the application to draw only the focus rectangle at the coordinates
specified by the rcItem member even though there are no items in the
control. This indicates to the user whether the list box or combo box
has the focus. How the bits are set in the itemAction member
determines whether the rectangle is to be drawn as though the list box
or combo box has the focus.
If you are not using owner/custom draw then all Windows common controls will draw the focus rectangle for you automatically.
Windows 2000 (and later) hide keyboard accelerators and focus rectangles by default unless you are interacting with the window by using your keyboard.
Windows enables applications to hide or show various features in its UI. These settings are known as the UI state. The UI state includes the following settings:
focus indicators (such as focus rectangles on buttons)
keyboard accelerators (indicated by underlines in control labels)
I'm working on an Windows Application which has to show an overlaying fixed positioned window ("PopUp") in the left corner of the MainFrame which will receive some Information if a user missed some input or if certain actions have been successfully.
The "PopUp" Titlebar shall have an Icon next to the Title (e.g. ->Icon<- "Error") and the standard X - Close-Button. The ClientArea will have an descriptive text of the occurred Message.
Additionally the standard Border of the PopUp shall be set to 1px(smaller than the default windows border)
The "PopUp" is derived from CWnd and created with WS_VISLBE | WS_CLIPSIBLINGS | WS_CHILD | WS_CAPTION in the OnCreate-Method of the Applications MainFrame Window
Now I need to set/shrink the default Border of my PopUp and add the Icon to the Titlebar of the PopUp.
Can someone give me some example code of how i can solve my issues?
I'm pretty new to c++ and MFC so far my research brought me to https://msdn.microsoft.com/en-us/library/windows/desktop/bb688195(v=vs.85).aspx
but i dont know where and how to use DwmExtendFrameIntoClientArea() but so far I've read I assume Dwm is the way to go to be able to solve both problems or is there another/totally different way? Am I on the right track?
Finally I was able to shrinkthe default Windows Border by overriding the handling of WM_NCCALCSIZE.
I will update this answer as soon as I solved how to put my Icon in the Titlebar.
As of now I'll explain how I shrink the windows border:
Add ON_WM_NCCALCSIZE() to your MessageMap of the desired Window and Implement OnNcCalcSize() (Class Wizard will help to set this up) as followed:
void YourCWndClass::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp)
{
if (bCalcValidRects){
CRect rcClient, rcWind;
GetClientRect(&rcClient);
GetWindowRect(&rcWind);
int border = (rcWind.right - rcWind.left - rcClient.right) / 2 - 1;
//-1: leaves 1px of the Windows Default Border Width erase to have no border
lpncsp->rgrc->left -= border;
lpncsp->rgrc->right += border;
lpncsp->rgrc->bottom += border;
}
CWnd::OnNcCalcSize(bCalcValidRects, lpncsp);
}
The WM_NCCALCSIZE Message is sent up on the Window Creation (when you call Create()/CreateEx() ) but at this point of time GetClientRect() and GetWindowRect() will not return the proper values therefore you need to check the Bool Parameter!!!
To trigger another WM_NCCALCSIZE to be able to work with the proper Window Rectangles call SetWindowPos() right after the window creation
if (!m_MessagePopOver->Create(NULL, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CAPTION, rect, this, NULL, NULL)){
TRACE0("failed to create MessagePopOver");
}
m_MessagePopOver->SetWindowPos(&wndTop, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
This will result in a window like this:
I'm making a custom caption bar with custom draw buttons by removing the window default bar with SetWindowLong(hWndParent, GWL_STYLE, 0). Everything is going good by now except I'm stuck at making my window minimize by clicking the taskbar programmatically. I'm trying the WM_ACTIVATEAPP right now but the window are unable to minimize properly.
This is the code for WM_ACTIVATEAPP for main window:
case WM_ACTIVATEAPP:
if(LOWORD(wParam) == FALSE)
SendMessage(hWndParent,WM_SYSCOMMAND,SC_MINIMIZE,NULL);
break;
When you left click the task bar,it will minimize BUT once you released the click.. the window will be restored.. Is there something missing? I want to make it minimize after you release the click.
Notes: I dint put the activate window code because the window seems to be able to restore itself by clicking the taskbar after being minimized with custom draw button.
You're probably not handling WM_NCACTIVATE as well. Try handling it, similar to this:
case WM_NCACTIVATE:
break;
case WM_ACTIVATEAPP:
if (LOWORD(wParam) == FALSE)
SendMessage(hWnd, WM_SYSCOMMAND, SC_MINIMIZE, NULL);
break;
Edit:
I must have missed the part of your question where you said you removed the default bar by setting the style to 0. That is definitely not the proper way to do it, you should do something along the lines of this, as found here:
LONG lStyle = GetWindowLong(hWnd, GWL_STYLE);
lStyle &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU);
SetWindowLong(hWnd, GWL_STYLE, lStyle);
After you do that you should no longer need to handle WM_ACTIVATEAPP or WM_NCACTIVATE to properly minimize/maximize the window.
Ok so I am using this code to hide the taskbar icon of a dialog based MFC application(VC++). The taskbar icon and the dialog box hide whenever I click on the cross or the close buttons. But I can’t get this one thing right. Whenever I hit the close or the cross button from title bar, the dialog box first flickers and shows a sort of intermediate dialog box and then hides. This is very annoying. I am posting my code here after two days of vain effort. So guys please help me. Thanks in advance.
void CMyAppDlg::OnBnClickedCancel()
{
// TODO: Add your control notification handler code here
CWnd* pWnd;
pWnd = AfxGetMainWnd();
RemoveTaskbarIcon(pWnd);
pWnd->ModifyStyle(WS_VISIBLE, 0);
mVisible = FALSE;
}
BOOL CMyAppDlg::RemoveTaskbarIcon(CWnd* pWnd)
{
LPCTSTR pstrOwnerClass = AfxRegisterWndClass(0);
// Create static invisible window
if (!::IsWindow(mWndInvisible.m_hWnd))
{
if (!mWndInvisible.CreateEx(0, pstrOwnerClass, _T(""),
WS_POPUP,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL, 0))
return FALSE;
}
pWnd->SetParent(&mWndInvisible);
return TRUE;
}
Here are the screen shots of dialog box. When I press the close or cross button, the dialog box which looks like this in the first place turns into this for like less than half a second and then disappears (hides).
If you show your dialog using CDialog::DoModal() the framework will make sure your dialog is shown. There is only one way to prevent a modal dialog from being shown:
BEGIN_MESSAGE_MAP(CMyDialog, CDialog)
ON_WM_WINDOWPOSCHANGING()
END_MESSAGE_MAP()
BOOL CHiddenDialog::OnInitDialog()
{
CDialog::OnInitDialog();
m_visible = FALSE;
return TRUE;
}
void CHiddenDialog::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos)
{
if (!m_visible)
lpwndpos->flags &= ~SWP_SHOWWINDOW;
CDialog::OnWindowPosChanging(lpwndpos);
}
I think Paul DiLascia recommended the following. This is for modal dialogs only.
The following code can be put in OnInitDialog to move the dialog off-screen. You will need to implement a method for moving it back on-screen when appropriate.
CRect DialogRect;
GetWindowRect(&DialogRect);
int DialogWidth = DialogRect.Width();
int DialogHeight = DialogRect.Height();
MoveWindow(0-DialogWidth, 0-DialogHeight, DialogWidth, DialogHeight);
The answer from l33t looks good and is probably better but this is an alternative.
Maybe an obvious thing, but what happens when you do the hide before you reparent the dialog? Also what if you don't directly modify the window style but use ShowWindow(SW_HIDE)?
Finally, have you tried switching the dialog's window style to WS_CHILD before calling SetParent() and/or maybe moving it out of the client area so that the window isn't shown any more (MoveWindow(-1000, -1000) or something like that).
I'm trying some of the new MFC functionality and i want the same thing that the TrayMenu project from Visual C++ Language Samples for Visual Studio 2010 does but in my machine (don't know if is only in my machine i try to find the same problem in the web but didn't find any similar report!!!) the menu appears in the background of the new win7 traynotifywwnd, and i can't seem to put it work right:
The code is simple:
void CTrayMenuDlg::OnTrayContextMenu ()
{
CPoint point;
::GetCursorPos (&point);
CMenu menu;
menu.LoadMenu (IDR_MENU1);
CMFCPopupMenu::SetForceShadow (TRUE);
HMENU hMenu = menu.GetSubMenu (0)->Detach ();
CMFCPopupMenu* pMenu = theApp.GetContextMenuManager()->ShowPopupMenu(hMenu, point.x, point.y, this, TRUE);
pMenu->SetForegroundWindow ();
}
I think that SetForegroundWindow is some how a fix for this problem, but it does not work, it stills show bewind the window where all the tray icon are hidden and displayed when we click in the little arrow (note that if the icon is displayed in the ToolbarWindow32 -not hidden - and we call the tray context menu then it all works fine, this problem only appear if the icon is hidden and is show using the little arrow in the ToolbarWindow32 and a window is displayed with the hidden icons - is this window that stays in front of my context menu...)
Has anyone find this problem? and there is any solution for this problem?
Thanks
I am not sure about this one but you can try adding:
// Set window position to topmost window.
pMenu->SetWindowPos(
&CWnd::wndTopMost,
0, 0, 0, 0,
SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE );
instead of pMenu->SetForegroundWindow ();
From MSDN:
Add ::SetWindowPos(pMenu->m_hWnd,HWND_TOPMOST,0,0,0,0,SWP_NOSIZE | SWP_NOMOVE);
before the pMenu->SetForegroundWindow ();
in CTrayMenuDlg::OnTrayContextMenu () function.
For me this worked!