I'm working on my first simple MFC project, but I'm struggling with one problem: want to set the focus of all CEdit boxes in one of the dialogs. My idea is when open the dialog, the focus to be on the first edit box and then to swap between them with 'tab'.
I saw the method SetFocus(), but I couldn't apply it correctly. Also I couldn't find a solution for implementing the order of the focus with a specific key.
Thanks in advance to everybody who takes time to help me!
You can set the focus to a given control when your dialog box is first shown by calling SetFocus in your OnInitDialog() function. However, if you do so, your OnInitDialog() must return FALSE:
BOOL MyDialog::OnInitDialog() {
CDialog::OnInitDialog(); // Call base class member
GetDlgItem(IDC_MYEDIT)->SetFocus();
//..
return FALSE; // Otherwise, the framework will reset the focus to its default
}
From the M/S documentation:
Return Value
Specifies whether the application has set the input focus to one of
the controls in the dialog box. If OnInitDialog returns nonzero,
Windows sets the input focus to the default location, the first
control in the dialog box. The application can return 0 only if it has
explicitly set the input focus to one of the controls in the dialog
box.
Related
In the source code generated by the template for a Dialog based MFC application the InitInstance() of the main application, derived from CWinApp, initializes the application environment and then creates the dialog that is the main application interface and displays it with DoModal(). When the displayed dialog returns, the application finishes and terminates.
In the main application interface dialog that is derived from CDialogEx there is a method OnInitDialog() which is called as part of initializing the dialog.
What is the difference between returning TRUE or returning FALSE from this method?
BOOL CMyTabDlgs::OnInitDialog()
{
CDialog::OnInitDialog() ;
// Some code
return true;
}
and
BOOL CMyTabDlgs::OnInitDialog()
{
CDialog::OnInitDialog() ;
// Some code
return false;
}
The OnInitDialog() member function is called by the MFC framework when it is processing a WM_INITDIALOG message.
The purpose of this member function is to provide a place to perform any special initialization of the dialog's controls and interface.
One of the events that can be done in the OnInitDialog() method is to set the focus to one of the controls in the dialog. This action allows the programmer to decide which control (button, edit window, combo box, etc.) displayed in the dialog should have the focus first.
Or the programmer can just allow the MFC framework to make that decision for them.
If the programmer sets the focus to a particular control, the OnInitDialog() method should return FALSE so that the MFC Runtime knows that the focus has already been set.
If the programmer does not set the focus to a particular control, the OnInitDialog() method should return TRUE so that the MFC Runtime knows that it needs to set the focus.
That is what the comments in the OnInitDialog() method skeleton created by the MFC template indicate as in the code sample from https://technet.microsoft.com/en-us/windows/fwz35s59(v=vs.60)
BOOL CSimpleDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
m_cMyEdit.SetWindowText(_T("My Name")); // Initialize control values
m_cMyList.ShowWindow(SW_HIDE); // Show or hide a control, etc.
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
The MSDN article CPropertySheet::OnInitDialog has a fuller explanation for the return value:
Specifies whether the application has set the input focus to one of
the controls in the property sheet. If OnInitDialog returns nonzero,
Windows sets the input focus to the first control in the property
sheet. The application can return 0 only if it has explicitly set the
input focus to one of the controls in the property sheet.
I have a CFormView SDI which calls and opens up a CDialog.
In the CDialog I have a button which has a bitmap displayed.
All works well, until I close the CDialog.
When I open up the same CDialog (using create function), the button appears, and the button's functionality is there, however the bitmap disappears.
Can someone please tell me why the bitmap on the button disappears on subsequent calls to CDialog?
Thank you in advance.
Here is the code:
In the CFormView I have a button that creates the CDialog:
void CTest4View::OnButton1()
{
m_dialog_calculator.Create(IDD_DIALOG1, GetDesktopWindow());
m_dialog_calculator.ShowWindow(SW_SHOW);
}
In the CDialog I have the bitmap put on the button in the InitDialog:
BOOL CCalculator::OnInitDialog()
{
CDialog::OnInitDialog();
if(!bitmapNew.LoadBitmap(IDB_BITMAP_NEW)){
MessageBox("problem in loadbitmap");
}
if(!m_button.SetBitmap(bitmapNew)){
MessageBox("problem in SetBitmap");
}
bitmapOpen.LoadBitmap(IDB_BITMAP_OPEN);
m_buttonOpen.SetBitmap(bitmapOpen);
//==========================
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
Upon further investigation, the problem seems to be in: m_button.SetBitmap(bitmapNew) since this returns FALSE. Can someone please help me?
Quick fix:
void CTest4View::OnButton1()
{
// only create the dialog once
if (m_dialog_calculator.m_hWnd==NULL)
m_dialog_calculator.Create(IDD_DIALOG1, GetDesktopWindow());
m_dialog_calculator.ShowWindow(SW_SHOW);
}
Additional information 1:
The information that OP provided in his question/code is quite little, so I actually have to recreate a similar test project to guess what is wrong with the missing bitmap. What I found is that the CDialog and CBitmap is being created multiple times when the button is pressed, this causes subsequent creation api call to fail, other than the first creation call. The result is some unexpected behavior as you can see now.
The program is supposed to generate some assertion errors when run in debug mode due to the creation failure but I guess the OP compiled it in release mode so all warnings are being suppressed.
The problem occurred because the calculator dialog is created as a modeless dialog as compared to a normal DoModal way of activation. The usual way of doing such modeless dialog is to create the dialog only once, by monitoring the m_hWnd member variable. When the user want the dialog to be dismissed, it is simply being hidden instead of being destroyed. This will avoid all the multiple creation problems altogether.
I guess presently, the calculator dialog is assumed to be closed and destroy by clicking the "X" button on the top right of dialog, well, actually it is only hidden but not actually being destroyed by the default handling of CDialog. The correct way to dismiss the modeless calculator dialog is thus to overide the OnClose event to hide it using ShowWindow(SW_HIDE). To activate it again, use ShowWindow(SW_SHOWNORMAL).
I want to make a button on an MFC tool bar that can be pressed and retain it's state until pressed again (like a check box) but I don't want a tick box. I'd ideally like a button that changes between two icons and uses DDV to change the value of a boolean on being pressed. How would I go about this.
As a side question I could really do with a good book on MFC. I've got Programming Windows with MFC 2nd edition, but was wondering if there was anything that went into a bit more detail?
Use ON_UPDATE_COMMAND_UI to set the state of the button. e.g. a typical handler will look like this:
BEGIN_MESSAGE_MAP(CMyView, CView)
ON_UPDATE_COMMAND_UI(ID_MY_BUTTON, OnUpdateMyButton)
END_MESSAGE_MAP()
...
void CMyView::OnUpdateMyButton(CCmdUI* pCmdUI)
{
// TODO: Add your command update UI handler code here
pCmdUI->SetCheck( isButtonPressed() );
}
With regard to good MFC documentation I recommend Professional MFC (Mike Blaszczak) - it's a little old but very good.
From the documentation of the CToolBar Class:
To create a check-box button, assign it the style TBBS_CHECKBOX or use a CCmdUI object's SetCheck member function in an ON_UPDATE_COMMAND_UI handler.
Draw a Radio Button on Dialog box.
Select Radio button & go to button Properties page.
Set Push Like property & set as "True"
Add event handler for the same control & take Boolean variable.
Use API -> "CheckDlgButton(IDC_RADIO1, 1);" for set status as per Boolean variable value.
for more details. visit below link.
https://www.codeproject.com/Articles/530/A-Better-Bitmap-Button-Class
If I click anywhere on the dialog window, like in the "background", or on a Static Text, the function OnLButtonDown() is fired. But if I click a ListBox/EditBox/Combo/Calendar/Checkbox etc is not fired.
I thought that because these have control variables atached to it, and the Static Text don't. But adding a new Listbox to my Dialog and testing, I see that it doesn't fire either, so now I am confused...
I added OnLButtonDown() with the Class Wizard, it appears in:
BEGIN_MESSAGE_MAP(CMFCTesting2Dlg, CDialogEx)
ON_WM_SYSCOMMAND()
// other handlers, etc
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
END_MESSAGE_MAP()
My function:
void CMFCTesting2Dlg::OnLButtonDown(UINT nFlags, CPoint point)
{
AfxMessageBox(CString("BUTTON DOWN"));
CDialogEx::OnLButtonDown(nFlags, point);
}
I tried calling CDialogEx:: ... before AfxMessageBox... but same result.
The CListBox item, has the Notify option set to True, as I seen some advices in other posts.
I suspect that the WM notification message is captured somehow by the ListBox, and not sent "forward" to my CMFCTesting2Dlg, but I understood that this should happen with the Notify option set to True, on the ListBox, no? (well, obviously, not...)
Sorry, I am new to dealing with WM in MFC.
BTW, I use Visual Studio 2010 Ultimate, and this is a Visual C++ - MFC- MFC Application - Dialog Based project.
How can I capture this mouse down event if clicked on a listbox / combo / etc?
On the LONG STORY, I am actually trying to accomplish this issue:
I have two listboxes (lets say), and I want to scroll them synchronously, when user scrolls one of them, others must scroll the same (or update in the next moment). And I thought of using on mouse down to track the position of every Listbox (with the GetTopIndex), and on mouse up, to GetTopIndex again and compare with the previous ones. If a change was made, then a listbox was scrolled and then update all listboxes with SetTopIndex. The unfriendly solution for the user, but simpler for me, would be clicking a button that does this verification / update, but its not elegant at all, and it can only set them at the same level, but can't determine which one was scrolled last time. This automatically scrolling of the listboxes should be made just for displaying, it is not important the selections in the listboxes. I tried using the Message Type in the Add Event Handler for the Listbox, but none that are displayed work for my problem, KillFocus and SetFocus, are not fired if the scroll-bar is dragged, only if an item in the listbox is clicked... and I didn't succeed on the others message type either, from the Add Event Handler.
Once a window handles a message, it stops being sent to the other windows beneath it. A static window doesn't handle a mouse down, so it goes to the dialog. The other controls all handle it in some fashion (setting focus at least) so it never gets to the dialog.
You can override the OnLButtonDown handler in each of the controls to do something else once they've finished their default handling in the base class. You might also get to see the message in the PreTranslateMessage method of the dialog.
As far as getting the List Controls to sync scrolling goes, your best bet would be to intercept WM_VSCROLL by subclassing CListCtrl or perhaps by PreTranslateMessage, and then calling SetScrollInfo on the other list. If the number of items in the lists are the same, it should be fairly simple.
I have the following situation.
There is a dialog with a check-box and a text-box. Check-box's click is bound to a function that toggles if the text-box is enabled or grayed out. It works fine but I also need to preset some values to the dialog before creating and displaying it. If the variable that is connected to the check-box is set to ture I want to disable the text-box.
I tried to accomplish this in different ways, but it all boils down to the fact that I can not change the GUI of the dialog before calling DoModal (I get assertion falure when I try).
This is probably a common problem, but I could bot find a solution online. Am I completely off track?
MyDialog d(this);
d.bFlag = TRUE; // Because it is true, I want the text-box to be disabled
// I could call a function of d here that would set the state of the text-box correctly,
// but an assertion falure would happen.
if (d.DoModal() == IDOK){
...
}
You need to override OnInitDialog function in your dialog class MyDialog and have the code to check the check box value and enable/disable the text box.