MFC (C++): Why control on top does not receive event? - c++

At design stage,
A (List Box) is drawn before B (List Ctrl)
A is invisible initially
A covers part of B
During runtime, a button toggles the visibility of A, and when A is visible places it on top of B (using SetWindowPos(...)).
When A is shown, it does not receive events in the overlapping area (e.g., when I click "item 4" and "item 5" in the figure below). Why and how to fix it?
The sample code can be accessed here https://138.197.210.223/test/test.zip.

I did check the code, and found that the problem was caused by the ::SetWindowPos() command in OnBnClickedCheck1(). You call it to solve a drawing problem, but you do so by changing the Z-Order, and this causes the B control to capture the input instead. So it must be removed, and the code in OnBnClickedCheck1() can be changed as shown below (I have simplified the syntax, and used MFC, rather than WinAPI commands):
void CTestDlgActXDlg::OnBnClickedCheck1()
{
m_list_A.ShowWindow(m_list_A.IsWindowVisible() ? SW_HIDE : SW_SHOW);
}
The drawing problem can be solved by setting the WS_CLIPSIBLINGS style in the resource script, as suggested in the comments:
.
.
LISTBOX IDC_LIST_A,114,36,48,42,LBS_SORT | LBS_NOINTEGRALHEIGHT | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP
CONTROL "",IDC_LIST_B,"SysListView32",LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP | WS_CLIPSIBLINGS,108,60,60,54
.
.
This way it works for me, the A control takes precedence over B, and sends LBN_SELCHANGE notifications, for any of its items clicked.
And something strange I have noticed, the DDX_Control(pDX, IDC_LIST_B, m_list_B); command in testdlg.cpp is run twice. Delete the 2nd call.
Weird UI design btw. 😀

Related

How to show CDockablePane after it has been closed

I understand CDockablePanes remember their state when the program is closed and then opened again, but I don't understand how I'm supposed to show a CDockablePane that has been closed in a previous use.
This is my initialisation code :
DWORD dwPaneStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CBRS_FLOAT_MULTI;
MyPane.Create(_T("MyPane"), this, CRect(0, 0, 0, 120), TRUE, ID_VIEW_MYPANE, dwPaneStyle | CBRS_BOTTOM));
MyPane.ShowPane(TRUE, FALSE, TRUE);
So this would create my pane and then set it to be shown, but for some reason I can't see it in my main frame... What am I missing?
Also, I would like to be able to show the pane when a certain button is pushed. I already have my MessageMap and OnButtonFct() ready. I just need to know how to show the pane.
Thanks!
I found it... it seems MFC saves the entire state of how the program was left in. So when the app is launched, the panel is shown, but then the app loads the last state and hides the panel. I was able to make it visible again by using the same line :
MyPane.ShowPane(TRUE, FALSE, TRUE);
on a button push event instead of during the creation.
There seems to also be a way to disable the automatic "Load last state" behaviour by adding the following in the CWinAppEx constructor.
m_bSaveState = FALSE;

How to prevent overlap of my context menu with the system menu in the Windows notification area?

I've seen a lot of "unofficial" workarounds to bypass this visual bug, but none of them seem to work correctly for me. Let me explain.
Say, I display my own system tray icon in the Windows notification area (by the clock.)
My program also supports displaying a context menu when a user right-clicks my tray icon. I implement it by trapping the WM_RBUTTONDOWN notification from the message handler specified in the uCallbackMessage parameter of the NOTIFYICONDATA. I then processing it as such:
//Show menu (ask to return results here)
int nRes = TrackPopupMenu(hMenu, TPM_RIGHTALIGN | TPM_TOPALIGN |
TPM_LEFTBUTTON | TPM_VERPOSANIMATION | TPM_HORNEGANIMATION | TPM_RETURNCMD,
pnt.x, pnt.y, 0, this->GetSafeHwnd(), NULL);
Unfortunately the code above, all by itself, does not allow the menu to be dismissed after a left-click somewhere outside of it.
To resolve this, the solution I found was this:
//Need this to bypass a glitch in Windows to remove popup menu from
//System Tray after mouse click outside of it
::SetForegroundWindow(this->GetSafeHwnd());
//Show menu (ask to return results here)
int nRes = TrackPopupMenu(hMenu, TPM_RIGHTALIGN | TPM_TOPALIGN |
TPM_LEFTBUTTON | TPM_VERPOSANIMATION | TPM_HORNEGANIMATION | TPM_RETURNCMD,
pnt.x, pnt.y, 0, this->GetSafeHwnd(), NULL);
PostMessage(WM_NULL, 0, 0);
But the "fix" above introduces an occasional additional bug.
For instance, here's a screenshot from Windows 8. Sometimes, I think it depends on what window had focus prior to this, when I right-click on my tray icon my context menu is displayed on top of the Windows default context menu, that looks like this:
Is there any way to resolve this visual bug of overlapping context menus?

How to run command radiobutton inside a container in a window?

How to run command radiobutton inside a container in a window?
I was looking for weeks on the internet but I do not think I conosco forums can help me with a library as sophisticated as windows.h. So I come to this forum for professional help.
I know how to create a radiobutton within the main program window. I also know how to create a radiobutton inside a container of radiobuttons, but I want to run the radiobutton command that is contained within the container.
It turns out that my program requires that when a radiobutton is selected style WM_GRAYED put an EDIT control.
The problem is not how to execute commands from a control contained in a container of controls within a main window.
My code:
hOptEnc = CreateWindowEx (
            0,
            "BUTTON",
            "Type input",
            WS_CHILD | WS_VISIBLE | BS_GROUPBOX,
            264,
            296
            100,
            64,
            hWndParent,
            (HMENU) CM_GROUPS,
            hInstance,
            NULL
            );
hRadioAssci = CreateWindowEx (
            0,
            "BUTTON",
            "Input Assci"
            WS_VISIBLE | WS_CHILDWINDOW | BS_AUTORADIOBUTTON,
            10
            17
            75,
            20
            hOptEnc,
            (HMENU) CM_RADIOASSI,
            hInstance,
            NULL
            );
hRadioHex = CreateWindowEx (
            0,
            "BUTTON",
            "Hex Input"
            WS_VISIBLE | WS_CHILDWINDOW | BS_AUTORADIOBUTTON,
            10
            37,
            75,
            20
            hOptEnc,
            (HMENU) CM_RADIOHEX,
            hInstance,
            NULL
            );
And each time the user dials an option as hex input, edit controls would change the coding. So I need the radiobutton run your command in the main window procedure function.
The container (the group box) has no effect on the radio button. It is for visual clarity only. Pass you main window to the radio buttons as their parent window.

How to mark a list control item as selected?

In a Win32 application I have a dialog with a list control which is defined is the dialog template:
CONTROL "",IDC_LIST_Attributes,"SysListView32",LVS_REPORT |
LVS_SINGLESEL | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,36,246,110
In the runtime I retrieve the handle to that control and perform different operations with it - remove all items, add items, etc. It works fine.
The problem is I can't programmatically mark an item as selected. I use the following code for that:
LVITEM lvItem;
lvItem.stateMask = stateMask;
lvItem.state = state;
SendMessage( windowHandle, LVM_SETITEMSTATE, indexToSelect, (LPARAM)&lvItem);
This code runs and no changes happen to the list control. when I clisk on items with a mouse they are selected allright. What am I missing?
Have you tried ListView_SetItemState Macro?
From the MSDN Link:
Items will only show as selected if
the list-view control has focus or the
LVS_SHOWSELALWAYS style is used.
Another Link that my help.

create a control programmatically using MFC

I just wonder how to do it.
I write :
CEdit m_wndEdit;
and in the button event handler (dialog app),
I write :
m_wndEdit.Create(//with params);
but I still don't see the control appear in the UI.
I actually wrote this in the button handler :
CWnd* pWnd = GetDlgItem(IDC_LIST1);
CRect rect;
pWnd->GetClientRect(&rect);
//pWnd->CalcWindowRect(rect,CWnd::adjustBorder);
wnd_Edit.Create(ES_MULTILINE | ES_NOHIDESEL | ES_READONLY,rect,this,105);
wnd_Edit.ShowWindow(SW_SHOW);
this->Invalidate();
id 105 doesn't exist. (I used it in the Create member function of CEdit). I just put it in there. isn't it supposed to be the id you want to give to the new control ? Should it already exist ?
Check with the following set of flags as the example mentioned in MSDN:
pEdit->Create(ES_MULTILINE | WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | ES_NOHIDESEL | ES_READONLY,
rect, this, 105);
The Invalidate() is not necessary
Add the WS_VISIBLE flag to your create flags, you don't need the ShowWindow
You are creating the button on the location where IDC_LIST1 is - you probably want to do pWdn->Destroy() after the GetClientRect()
The id you pass to Create() can be anything, of course if you want to handle messages from this button later you'll need to use the correct id. In that case it's easiest to manually add an entry to resource.h.
What do you mean with 'I put this code in the button event handler' - which button? A different one from the one you're trying to create, I may hope? Does your code get called at all, does it stop when you put a breakpoint in? What's the value of wnd_Edit->m_hWnd after the call to Create()?
wnd_Edit is a member of your dialog, right, and not a a function local variable?
What is wnd_Edit exactly? If it's a local variable in that function, that is likely the problem. The CWnd destructor destroys the window associated with the CWnd. So when wnd_Edit goes out of scope, the edit box is destroyed too.
If that's not it, check the return value of Create(). Is it NULL? If it is, check the value of GetLastError().