MFC: CListCtrl.EnableWindow(FALSE), but still scrollable? [duplicate] - mfc

This question already has an answer here:
How to disable the CListCtrl select option
(1 answer)
Closed 7 years ago.
I have a CListCtrl list box which I would like to toggle betwen full functionality, and being read-only (ie the user can not change the selection).
The member function CListCtrl.EnableWindow(FALSE) seems designed for this, except that when I call
m_listCtrl.EnableWindow(FALSE);
GetDlgItem( IDC_LIST_CTRL_EDIT )->EnableWindow(FALSE);
the scrollbars on it stop working (assuming I have more content than will fit in the CListCtrl).
Is there an elegant way to achieve the read-only-but-still-scrolls behaviour, other than overriding mouse handlers, or resetting the selection on each page refresh?

You can accomplish this by deriving your own class from CListCtrl and handling the LVN_ITEMCHANGING notification. See my sample code below...
void MyClistCtrl::OnLvnItemchanging(NMHDR *pNMHDR, LRESULT *pResult)
{
*pResult = FALSE;
LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
// TODO: Add your control notification handler code here
// If there is no selection allowed, prevent the item from changing
if ((pNMLV->uNewState & LVIS_SELECTED) /* check flag to if it should be read only ie check radiobutton state*/)
{
*pResult = TRUE;
}
}
The code above will unconditionally prevent a selection while still allowing the scroll bar to function. The ability to control this behavior can be added to the "if" statement (eg. checking a flag tied to a radio button).

Related

MFC Rich Edit Control 2.0 receiving click event

I was hoping someone out there would help me with my predicament I ran into. Essentially I have a Checkbox and a RichEditControl next to each other. I want to be able to know when a user has clicked on my RichEditControl so i can send a message to my checkbox to flag it on and off.
At first i tried to overlay my checkbox with empty text to act as a "blank" background for my RichEditControl so i wouldn't have to worry about sending messages left and right. No matter what i tried the "blank" background would overlap the RichEditControl text and leave it completely blank.
I searched on here for some help and i found this which is exactly what I ran into. I understand what he is saying but don't have the knowledge to implement what they said.
Right now I'm playing around with EN_LINK to attempt to capture a message so i can tell my checkbox to flag itself.
BEGIN_MESSAGE_MAP(TempInit, CDialog)
ON_NOTIFY(EN_LINK, IDC_TempInitMsg, &TempInit::OnEnLinkTempinitmsg)
END_MESSAGE_MAP()
void TempInit::OnEnLinkTempinitmsg(NMHDR *pNMHDR, LRESULT *pResult)
{
ENLINK *pEnLink = reinterpret_cast<ENLINK *>(pNMHDR);
// TODO: Add your control notification handler code here
// TODO: Add your control notification handler code here
radioClicked = !radioClicked;
if (radioClicked == true)
{
GetParent()->SendMessage(WM_MYRADIOCLICKED, CHECKENABLED, 0);
}
else
{
GetParent()->SendMessage(WM_MYRADIOCLICKED, CHECKDISABLED, 0);
}
}
*pResult = 0;
}
I'm sorry in advance if this is totally the wrong way to go about this. I've been googling for a few hours and have come empty handed. If anyone has any other method please help me if possible. I can post more code if what i have above isn't enough.
Steven,
One way to go about this would be to handle the EN_MSGFILTER notification from the rich edit control. I can't provide you any code to show you how to do this off hand but here's the documentation for the Notification messages from that the Rich edit control generates. Simply handle it the same way your doing with your radio button.
This will check the check box when the Rich Edit Ctrl has the focus and untick
it when it losses the focus.
BEGIN_MESSAGE_MAP(TempInit, CDialogEx)
ON_EN_SETFOCUS(IDC_RICHEDIT21, &TempInit::OnEnSetfocusRichedit21)
ON_EN_KILLFOCUS(IDC_RICHEDIT21, &TempInit::OnEnKillfocusRichedit21)
END_MESSAGE_MAP()
void CMFCApplication1Dlg::OnEnSetfocusRichedit21()
{
CButton* pCheckBox = (CButton*)GetDlgItem(IDC_CHECK1);
pCheckBox->SetCheck(1);
}
void CMFCApplication1Dlg::OnEnKillfocusRichedit21()
{
CButton* pCheckBox = (CButton*)GetDlgItem(IDC_CHECK1);
pCheckBox->SetCheck(0);
}

MFC - Changing dialog item focus programmatically

I have a Modeless dialog which shows a bunch of buttons; some of these are customized to draw stuff with GDI.
Now, when the user clicks on a customized one under certain conditions, a message box appears to alert user of the error and this is fine.
The problem is that after accepting the Message Box (showed as MB_ICON_ERROR), everywhere I click in the dialog, I always get the error message as if the whole dialog send the message to the customized button and the only way to get rid this is to press tab and give the focus to another control.
This is a strange behaviour and knowing why happens wouldn't be bad, but a simple workaround for now should do the job.
Since the moment that is probably a matter of focus, I've tried to set it on another control (in the owner dialog) by doing:GetDlgItem( IDC_BTN_ANOTHER_BUTTON )->SetFocus();
and then, inside the customized control by adding:KillFocus( NULL );but had no results.
How should I use these functions?
Thanks in advance.
PS: if I comment the AfxMessageBox, the control does not show this bizarre behaviour.
EDITI'll show some code as requested.
// This is where Message Box is popping out. It is effectively inside the dialog code.
void CProfiloSuolaDlg::ProcessLBtnDownGraphProfilo(PNT_2D &p2dPunto)
{
// m_lboxProfiles is a customized CListBox
if(m_lboxProfiles.GetCurSel() == 0)
{
// This profile cannot be modified.
/*
CString strMessage;
strMessage.Format( _T("Default Profile cannot be edited.") );
AfxMessageBox( strMessaggio, MB_ICONERROR );
*/
return;
}
// Selecting a node from sole perimeter.
SelectNodo(p2dPoint);
}
Actually, the message is commented to keep the dialog working.
// This is inside the customization of CButton
void CMyGraphicButton::OnLButtonDown(UINT nFlags, CPoint point)
{
PNT_2D p2dPunto;
CProfiloSuolaDlg* pDlg = (CProfiloSuolaDlg*)GetParent();
m_pVD->MapToViewport(point,p2dPunto);
switch(m_uType)
{
case GRF_SEZIONE:
pDlg->ProcessLBtnDownGraphProfilo(p2dPunto);
break;
case GRF_PERIMETRO:
pDlg->ProcessLBtnDownGraphPerimetro(p2dPunto);
break;
}
CButton::OnLButtonDown(nFlags, point);
}
Since you are handling the button down event in the button handler for the custom control, you don't need to call the base class. Just comment out CButton::OnLButtonDown(nFlags, point).

MFC: CMFCToolBar SetButtonStyle not wirking with style TBBS_PRESSED?

byIs there are bug in control ? or I am doing something wrong ?
In .h
CMFCToolBar m_wndToolBar;
in message map
ON_COMMAND(ID_MYID, &CMainFrame::OnToolBar)
void CMainFrame::OnToolBar()
{
int nIndex = m_wndToolBar.CommandToIndex(ID_MYID);
UINT nState = m_wndToolBar.GetButtonStyle(nIndex);
if(nState & TBBS_PRESSED)
nState &= ~TBBS_PRESSED;
else
nState |= TBBS_PRESSED;
m_wndToolBar.SetButtonStyle(nIndex,nState);
m_wndToolBar.InvalidateButton(nIndex);
}
By clicking on button I need to set button pressed, and when user clicked again, button become unpressed.
Nothing happens by clicking on button :(
Just create an ON_UPDATE_COMMAND handler for the specific item.
Use pCmdUI->SetCheck to Signal the down or Up state.
The MFC updates tool bars and menus never directly. They ask the Framework to update the state of the Buttons and menu items.
Your description indicates that you want the button to have the behavior of a "check box". If that is correct, make sure you specify TBBS_CHECKBOX for the button style. You should not need to manually handle rendering the check box state each time the button is pressed.

Clistctrl selection detect

I've been playing with the list view and came across this post: How to detect a CListCtrl selection change?
However the code used there has a major flow, it doesn't work with multiple selection (as pointed out in that thread). So my question is how can I make the code work with multiselection (eg. selection with shift or ctrl)?
I've written a handy function to see if your OnItemChanged notification was due to a selection change:
BOOL IsItemSelChanged(NMLISTVIEW* pNMListView)
{
// call this from your OnItemchangedMyListCtrl function in your dialog class
if(!(pNMListView->uChanged & LVIF_STATE))
{
return(FALSE);
}
if((pNMListView->uOldState & LVIS_SELECTED) == (pNMListView->uNewState & LVIS_SELECTED))
{
return(FALSE);
}
return(TRUE);
}
Handle LVN_ITEMCHANGED and LVN_ODSTATECHANGED, all you needed...
If a list-view control has the LVS_OWNERDATA style, and the user
selects a range of items by holding down the SHIFT key and clicking
the mouse, LVN_ITEMCHANGED notifications are not sent for each
selected or deselected item. Instead, you will receive a single
LVN_ODSTATECHANGED notification, indicating that a range of items has
changed state.

How to make focus remain on all list control on same dialog box?

I have 3 list control on one dialog box but only one is showing focus.
if i clicked on 2nd list control then focus disaappear from 1st one.
Means at a time only one list showing focus.
How to make focus remain on all list control on same dialog box?
I don't think that this is technically possible. 'Focus' is an attribute that can only be applied to an individual element.
Think of it in terms of 'focus' is the element that the user is currently interacting with. How would a user be expected to interact with 3 distinct elements at the same time?
As Brian says - focus can only be on one control at time. I'm guessing you are trying to change the other list controls based on the first list box. One way to do it is to associate a variable with each list control, like mListCtrl1, mListCtrl2. Then add a handler for the NM_CLICK event, and have some code like this:
void CTabTestDlg::OnNMClickList3(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMITEMACTIVATE pNMItemActivate = (LPNMITEMACTIVATE)(pNMHDR);
// TODO: Add your control notification handler code here
*pResult = 0;
UpdateData(true);
DWORD dwData = mListCtrl1.GetItemData(pNMItemActivate->iItem);
int max = mListCtrl2.GetItemCount();
for (int i=0;i<max;i++)
{
DWORD dwData2 = mListCtrl2.GetItemData(i);
if (dwData==dwData2)
{
mListCtrl2.SetItemState(i,LVIS_SELECTED,LVIS_SELECTED);
break;
}
}
UpdateData(false);
}
Note that I have the control set to "Always show selection", and "Single selection"