Input as float number - visual-studio-2010

I am want to make a calculator on visual studio 2010 using MFC application. For this i used a dialog box to create calculator and add buttons and edit boxes. As we know that edit boxes are used as input. So i want to make the input as float input. So that's what the below sentence is :
There is a sentence : First choose two edit boxes and placed them on dialog. Use the Class Wizard from the View menu to connect each to a float, value number1 or number2 .
Edit boxes are there. Now how to connect them to a float, value number 1 ? What's the procedure?
Thanks

If I understand your question correctly, you want to bind the edit boxes to float member variables of your dialog box. This is called dialog data exchange. In this answer, I will try to explain how to achieve this with code (it should be more helpful than teaching Class Wizard).
Basically, you define two float member variables in your dialog box, along with their accessors:
class CYourDialog : CDialog
{
// ...
public:
float GetNumber1() const {
return m_number1;
}
void SetNumber1(float val) {
m_number1 = val;
}
float GetNumber2() const {
return m_number2;
}
void SetNumber2(float val) {
m_number2 = val;
}
private:
float m_number1;
float m_number2;
};
Then, you override the DoDataExchange() method of the dialog box, and call DDX_Text() from there to bind the member variables to your controls:
void CYourDialog::DoDataExchange(CDataExchange *dx)
{
CDialog::DoDataExchange(dx);
DDX_Text(dx, IDC_NUMBER1_CONTROL_ID, m_number1);
DDX_Text(dx, IDC_NUMBER2_CONTROL_ID, m_number2);
}
From there, the MFC framework will automatically populate the edit boxes with the values of the member variables on dialog initialization, and update the member variables with the values of the edit boxes when the OK button is clicked. This is a good thing because you only have to read and write to these member variables instead of manipulating the edit boxes directly.

Related

Questions regarding GetWindowPlacement return data

I'm a bit unsure of the meaning of some of the return values from a call to the GetWindowPlacement() function, so I'd like your help, please.
I'll be calling this to obtain the normal dimensions of a hidden window.
First, where do the values of the showCmd field come from? In the Microsoft documentation of the return structure (WINDOWPLACEMENT structure, all the descriptions of the possible values use verbs/action words; e.g., "SW_MAXIMIZE: Maximizes the specified window", or "SW_SHOWNOACTIVATE: Displays a window in its most recent size and position."
I want to obtain the dimensions of the hidden window without unhiding/restoring it first, so with the verbs it seems that I would have to call SetWindowPlacement() with showCmd set to SW_SHOWNOACTIVATE before calling GetWindowPlacement. Is that correct?
So do I understand correctly that the primary (and perhaps only) way that field gets its various values is by an explicit call to SetWindowPlacement() somewhere?
My second question relates to the rcNormalPosition return values. Do those data include the window decorations, or are they client values?
Thank you for your time!
The meaning of the showCmd member of the WINDOWPLACEMENT struct is a bit confusing because Win32 is reusing the SW_* commands used by ShowWindow().
Luckily, the meaning is documented on the GetWindowPlacement() function.
If the window identified by the hWnd parameter is maximized, the
showCmd member is SW_SHOWMAXIMIZED. If the window is minimized,
showCmd is SW_SHOWMINIMIZED. Otherwise, it is SW_SHOWNORMAL.
So, based on which of those 3 values is returned, you can tell whether the window is currently maximized, minimized or, normal (restored). And if you'd like to know what the normal placement is, you can just use the rcNormalPosition member. You do not need to call SetWindowPlacement() at all.
However, heed the warning that GetWindowPlacement() returns workspace coordinates rather than screen coordinates, which differ based on taskbar position and size. This is not a problem if you are only using the coordinates returned by GetWindowPlacement() to call SetWindowPlacement(). Otherwise, you might have to find a way to convert from workspace to screen coordinates.
I found these 2 functions to work for me.
void MyDialog::LoadDialogPlacement()
{
static WINDOWPLACEMENT last_wp = {};
// Load last stored DB version
WINDOWPLACEMENT *wp = new WINDOWPLACEMENT;
GetStoredWindowPlacement(&wp);
if (memcmp((void *)&last_wp, (const void *)wp, sizeof(WINDOWPLACEMENT)) == 0) return;
memcpy((void *)&last_wp, (const void *)wp, sizeof(WINDOWPLACEMENT));
SetWindowPlacement(wp);
delete[] wp;
}
void MyDialog::SaveDialogPlacement()
{
static WINDOWPLACEMENT last_wp = {};
if (IsWindowVisible())
{
WINDOWPLACEMENT wp = {};
wp.length = sizeof(WINDOWPLACEMENT);
GetWindowPlacement(&wp);
if (memcmp((void *)&last_wp, (const void *)&wp, wp.length) == 0) return;
memcpy((void *)&last_wp, (const void *)&wp, wp.length);
StoreWindowPlacement(&wp);
}
}

Implementing multiple dialogs with similar processing

We have multiple dialogs in our MFC program that are very similar. Each one of these dialogs contain similar controls (i.e., they all contain a name, date, address, etc). Because of this, we've had to code out the display code multiple times for the windows despite the fact that the processing of these controls is identical. I'm looking for suggestions on how to change up our guis so that i have to only do the processing at one spot and not have to do it multiple times.
My thought was to have a class that would do the processing and pass pointers to the controls to display to that class, though i feel that is not a very good OO design.
Thoughts?
Create a base class derived from CDialog (say CMyDlgBase), place all your common functions there and derive your dialog classes from CMyDlgBase instead of CDialog.
You can now call the functions in CMyDlgBase as if they were declared directly in your dialog classes.
EDIT sample code to validate an item common to dialogs (CDlg1 and CDlg2 are derived from CMyDlgBase), error checking code not included:
BOOL CMyDlgBase::ValidateName(UINT nID)
{ CString ss;
CEdit *pEdit = GetDlgItem(nID);
pEdit->GetWindowText(ss);
if (ss.Find(_T("A")) < 0) // some kind of validation
{ MessageBox(_T("Name should contain the character 'A'"));
pEdit->SetFocus();
return FALSE;
}
return TRUE;
}
CDlg1::OnOK()
{ if (!ValidateName(IDC_DLG1_NAME)) // resource id value = 101
return;
CDialog::OnOK(); // This will close the dialog and DoModal will return.
}
CDlg2::OnOK()
{ if (!ValidateName(IDC_DLG2_NAME)) // resource id value = 102
return;
CDialog::OnOK(); // This will close the dialog and DoModal will return.
}

Edit Control not updating with Spin Control MFC

I am trying to use an edit control along with a spin control using MFC visual studio .net 2003. I have carried out the basic settings for the spin control like setting the "AutoBuddy" property and "SetBuddyInteger" property to True so that the Spin control works in coordination with the edit control next to it. In my Spin control's event handler, I am facing a problem when I am trying to call my Invalidate() function. The float value in my edit control does not update and stays zero. If I remove the Invalidate(), then the value increments but my paint function is not updated obviously. A code of the following is given below:
void CMyDlg::OnSpinA(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMUPDOWN pNMUpDown = reinterpret_cast<LPNMUPDOWN>(pNMHDR);
// TODO: Add your control notification handler code here
UpdateData();
m_A = m_ASpinCtrl.GetPos(); // m_A is my edit control float value variable
Invalidate(); // Invalidate is to be called to update my paint function to redraw the drawing
UpdateData(false);
*pResult = 0;
}
I have carried out the tab order correctly as well for the two controls.
Any suggestions on where I am going wrong?
Thanks in advance.
If you just want to have a spinning integer, you don't have to override anything.
The spin control has to be right next to the edit control in the tab order. With AutoBuddy that's all you have to do.
m_A when getting the position back would do something weird and would not return you the correct value. Try using the pointer to get your position and value and then carry out the invalidate().
{
LPNMUPDOWN pNMUpDown = reinterpret_cast<LPNMUPDOWN>(pNMHDR);
// TODO: Add your control notification handler code here
UpdateData();
CString tempStr;
m_A += pNMUpDown->iDelta;
tempStr.Format("%f",m_A);
m_ACtrl.SetWindowText(tempStr); // Like a CEdit m_ACtrl to display your string
Invalidate();
UpdateData(false);
*pResult = 0;
}
This should work perfectly well. Let me know if you still get any problems.

How to redirect a WM_KEYDOWN message to another control in MFC?

I'm on a roll today with MFC! :D
I have a text box and a list view control.
When the user presses the VK_UP and VK_DOWN keys in the text box, I would like this to happen:
Do some stuff.
Have the list view control also process the message (to highlight the previous/next item).
I want the list view to wrap around the current selection, if the key press is the first in its sequence.
Do some more stuff.
I tried subclassing my edit box in my dialog:
class MyEditBox : public CWnd
{
bool allowWrap;
afx_msg void OnKeyUp(UINT, UINT, UINT) { this->allowWrap = true; }
afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
CListCtrl &listView = static_cast<CListView *>(
this->GetParent()->GetDlgItem(IDC_LIST_VIEW))->GetListCtrl();
if (nChar == VK_UP || nChar == VK_DOWN)
{
int iSelBefore = listView.GetNextItem(-1, LVNI_SELECTED);
this->GetParent()->GetDlgItem(IDC_LIST_VIEW)
->OnKeyDown(nChar, nRepCnt, nFlags); //Oops! Protected member :(
int iSelAfter = listView.GetNextItem(-1, LVNI_SELECTED);
if (iSelBefore == iSelAfter && // Did the selection reach an end?
this->allowWrap) // If so, can we wrap it around?
{
int i = a == 0 ? listView.GetItemCount() - 1 : 0;
listView.SetItemState(i, LVIS_SELECTED | LVIS_FOCUSED,
LVIS_SELECTED | LVIS_FOCUSED);
}
}
this->allowWrap = false;
}
}
but OnKeyDown() is a protected member, so I can't just call it on another control.
Is there a better way to solve this than manually sending the command with SendMessage? Should I change my design, e.g. subclass something else, etc.?
Your intention is to select previous or next item in list control, right? Then you should call the method to do that directly instaed of asking the CListCtrl to "process" your message.
You may call CListCtrl::SetSelectionMark and CListCtrl::SetItemState to select next or previous keystroke. Example:
cListCtrl.SetSelectionMark(nIndex);
cListCtrl.SetItemState(nIndex, LVIS_SELECTED | LVIS_FOCUSED, 0xFF);
You can handle Key Down, Key Up as well as Page Down, Page Up, End, Home or any any key from edit box. You need to do calculation, though.
Or you can just SendMessage. There is no need to call OnKeyDown directly. Let the framework call it for you when you send the message.
I am seeing also other ways to solve this:
Derive a class from CListCtrl called MyListCtrl and choose one of two things:
1.1 Declare MyEditBox as a friend and now you can call the protected methods on MyEditBox
1.2 Add public methods CallOnKeyDown(...) and CallOnKeyup(...) to it that only do what is needed.
And when creating the control, instance a MyListCtrl instead of a CListCtrl. Also replace the listView variable you have shown here to be a MyListCtrl and use the methods you have now available
Use PreTranslateMessage(...). I think this "hammer" solution is worse than sending a message.

How to use a CTabCtrl in a MFC dialog based application?

I need to do something which i expected to be was simple - create a tab control which has 2 tabs, implying 2 modes of operation for my app. When user clicks on Tab1, he'll be presented with some buttons and textboxes, and when he clicks Tab2, some other input method. I noticed that there was a CTabCtrl class thats used in MFC to add tabs.
However, once I added the tab ctrl using the UI designer, I couldn't specify how many tabs there'll be using property window. Searching on the net, I found some examples but all of them required you to derive from CtabCtrl , create 2 or more child dialogs etc and to write your own custom class. My question is, since I want to do something so basic, why couldn't I do it using the familiar Add Event handler/Add member variable wizard and then handle everything else inside my app's class ? Surely, the default CTabCtrl class can do something useful without needing to derive from it ?
Forget about CTabCtrl and use CMFCTabCtrl which is much easier to work with (this is assuming you are working on VS2008 SP1).
Failing that, you seem to misunderstand how the tab control works. It only provides the 'tab strip' at the top and sends messages when the user clicks on another one. It doesn't provide you with 'tab canvases' on which you can put controls. Showing and hiding the controls on the tab is something that the programmer needs to take care of. The resource editor provides little support there. Like Stewart says, the most common way of working is to have child dialogs in your tab and hide all of them except the one of the current tab.
You don't need to derive from CTabCtrl, you can also implement the switching behavior in the window that is the parent of the CTabCtrl.
The MFC tab control is a pretty thin wrapper over the win32 tab control, which works in pretty much the way you describe. It is a window, which provides switching between child windows using tabs. As it happens, in straight win32 this is the most useful way for it to work. If you want to do something more sophisticated than switching between individual windows, you do this by using child dialogs. MFC doesn't do a great deal to help you, but deriving from CTabCtrl and using child dialogs is really not very difficult to do, although if you're used to the way WinForms does tab controls it does seem unnecessary.
If you want the tab control at the root of the dialog, with no other controls along side it, you might want to look at CPropertySheet (http://msdn.microsoft.com/en-us/library/d3fkt014(VS.80).aspx) which is probably simpler to use. Unless you want to use any of the wizard functionality you don't even need to derive from it - you just create a couple of child dialog classes, then in the place where you want to create the property sheet, make an object, add the pages to it and invoke it.
The approach I took with an MFC dialog that contained a CTabCtrl was to derive a small class to manage the tab control and used dialog templates to create the actual tab window contents.
This is still being worked on so the source code is not very clean however here are some pieces. For instance CTabCtrlDialog needs constructor and destructor in order to release object which may have been created.
In the resource file I have a dialog template with a tab control followed by three dialog templates for each of the different tab content windows inserted into the tab control. While the dialog displaying the tab control has the WS_POPUP style, the dialog templates for the tab windows that are inserted into the tab control have a WS_CHILD style instead. This change makes the tab windows child windows so that when the dialog is moved, everything stays lined up properly with no further effort on my part.
In my case the tab windows which are inserted into the tab control display a set of check boxes to indicate various operational parameters. Using a dialog template approach makes it very easy to create the necessary tab window content.
I derive a class from CTabCtrl that extends the standard MFC class with an additional method for inserting into the tab control a tab window based on a specified dialog template id. Since this is just a single dialog, I just put this class into the same files, .h and .cpp, as the dialog components themselves.
class CTabCtrlDialog : public CTabCtrl
{
public:
void InsertItemDialogTemplate (UINT nIDTemplate, int nItem, TCITEM* pTabCtrlItem);
public:
struct {
UINT nIDTemplate;
CDialog *pDialog;
} m_pDialogData[10];
};
The method InsertItemDialogTemplate() looks like:
/*
* InsertItemDialogTemplate ()
*
* Insert into a tab control a tab pane based on the specified dialog template. The
* dialog template describes what the tab pane looks like so far as controls, etc.
*
* NOTE: The STYLE description must be WS_CHILD and not WS_POPUP. Also the dialog
* needs to have as its top coordinate some distance in pixels so that the
* various tab descriptions are visible. For instance an example dialog
* template in the resource file may look like:
* IDD_CASHIER_TAB_ONE DIALOGEX 0, 10, 178, 113
* STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
* FONT 8, "MS Shell Dlg", 400, 0, 0x1
* BEGIN
* LTEXT "Dialog Tab one",IDC_STATIC,6,44,90,17
* END
*
**/
void CTabCtrlDialog::InsertItemDialogTemplate (UINT nIDTemplate, int nItem, TCITEM* pTabCtrlItem)
{
InsertItem (nItem, pTabCtrlItem);
m_pDialogData[nItem].nIDTemplate = nIDTemplate;
m_pDialogData[nItem].pDialog = new CDialog ();
m_pDialogData[nItem].pDialog->Create (nIDTemplate, this);
m_pDialogData[nItem].pDialog->ShowWindow (FALSE);
}
For handling tab selection which displays the various tabs I have the following message map and then the two event handlers in the dialog.
BEGIN_MESSAGE_MAP(CDiaCashierEdit, CDialog)
ON_NOTIFY(TCN_SELCHANGE, IDC_TAB_CASHIER_EDIT_STATUS, &CDiaCashierEdit::OnTcnSelchangeTabCashierEditStatus)
ON_NOTIFY(TCN_SELCHANGING, IDC_TAB_CASHIER_EDIT_STATUS, &CDiaCashierEdit::OnTcnSelchangingTabCashierEditStatus)
END_MESSAGE_MAP()
void CDiaCashierEdit::OnTcnSelchangeTabCashierEditStatus(NMHDR *pNMHDR, LRESULT *pResult)
{
// TODO: Add your control notification handler code here
*pResult = 0;
int i = TabCtrl_GetCurSel(pNMHDR->hwndFrom);
m_TabCtrl.m_pDialogData[i + 1].pDialog->ShowWindow (TRUE);
}
void CDiaCashierEdit::OnTcnSelchangingTabCashierEditStatus(NMHDR *pNMHDR, LRESULT *pResult)
{
// TODO: Add your control notification handler code here
*pResult = 0;
int i = TabCtrl_GetCurSel(pNMHDR->hwndFrom);
m_TabCtrl.m_pDialogData[i + 1].pDialog->ShowWindow (FALSE);
}
In the DoDataExchange() method of the dialog I have the following which creates first the tab control and then creates each of the tab windows and inserts them into the tab control.
void CDiaCashierEdit::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_EDIT_CASHIER_NAME, m_CashierName);
DDX_Control(pDX, IDC_EDIT_CASHIER_SUPNO, m_SupervisorId);
DDX_Control(pDX, IDC_EDIT_CASHIER_TEAMNO, m_TeamNumber);
DDX_Control(pDX, IDC_EDIT_CASHIER_GCSTART, m_GuestCheckStart);
DDX_Control(pDX, IDC_EDIT_CASHIER_GCEND, m_GuestCheckEnd);
DDX_Control(pDX, IDC_TAB_CASHIER_EDIT_STATUS, m_TabCtrl);
if (pDX->m_bSaveAndValidate) {
m_CashierName.GetWindowText (m_paraCashier.auchCashierName, 20);
m_paraCashier.usSupervisorID = m_SupervisorId.GetWindowTextAsInt();
m_paraCashier.uchTeamNo = m_TeamNumber.GetWindowTextAsInt();
m_paraCashier.usGstCheckStartNo = m_GuestCheckStart.GetWindowTextAsInt();
m_paraCashier.usGstCheckEndNo = m_GuestCheckEnd.GetWindowTextAsInt();
for (int i = 0; i < sizeof(m_TabItemOneStatus)/sizeof(m_TabItemOneStatus[0]); i++) {
int iTab = m_TabItemOneStatus[i].sTabItem;
int iDlg = m_TabItemOneStatus[i].iDlgItem;
int iOffset = m_TabItemOneStatus[i].sOffset;
CButton *p = (CButton *) m_TabCtrl.m_pDialogData[iTab].pDialog->GetDlgItem(iDlg);
if (p->GetCheck()) {
m_paraCashier.fbCashierStatus[iOffset] |= m_TabItemOneStatus[i].uchBit;
} else {
m_paraCashier.fbCashierStatus[iOffset] &= ~(m_TabItemOneStatus[i].uchBit);
}
}
} else {
m_CashierName.SetWindowText(m_paraCashier.auchCashierName);
m_SupervisorId.SetWindowTextAsInt (m_paraCashier.usSupervisorID);
m_TeamNumber.SetWindowTextAsInt (m_paraCashier.uchTeamNo);
m_GuestCheckStart.SetWindowTextAsInt (m_paraCashier.usGstCheckStartNo);
m_GuestCheckEnd.SetWindowTextAsInt (m_paraCashier.usGstCheckEndNo);
m_TabCtrl.InsertItemDialogTemplate (IDD_CASHIER_TAB_ONE, 1, &m_TabItemOne);
m_TabCtrl.InsertItemDialogTemplate (IDD_CASHIER_TAB_TWO, 2, &m_TabItemTwo);
m_TabCtrl.InsertItemDialogTemplate (IDD_CASHIER_TAB_THREE, 3, &m_TabItemThree);
for (int i = 0; i < sizeof(m_TabItemOneStatus)/sizeof(m_TabItemOneStatus[0]); i++) {
int iTab = m_TabItemOneStatus[i].sTabItem;
int iDlg = m_TabItemOneStatus[i].iDlgItem;
int iOffset = m_TabItemOneStatus[i].sOffset;
CButton *p = (CButton *) m_TabCtrl.m_pDialogData[iTab].pDialog->GetDlgItem(iDlg);
if (m_paraCashier.fbCashierStatus[iOffset] & m_TabItemOneStatus[i].uchBit) {
p->SetCheck (1);
} else {
p->SetCheck (0);
}
}
m_TabCtrl.m_pDialogData[1].pDialog->ShowWindow (TRUE);
}
}

Resources