How to call function when I choose line from ComboBox in C++? - c++

I wanted to call function by choosing line from ComboBox, but I don't know how to write it properly
void __fastcall TForm1::ComboBox1Change(TObject *Sender) {
if (ComboBox1.Lines.Count == 1) {
mode = 1;
}
else if (ComboBox1.Lines.Count == 2) {
mode = 0;
}

Check value of ComboBox::SelectedIndex property if it is Visual C++.
Check value of TComboBox::ItemIndex field if it is Embarcadero C++ Builder.
Depending on the value of this property take appropriate action.

Related

MFC Dialog Data Validation reverting data on failure

Has anyone found a way to revert a value on an editbox if it fails validation? If the value is invalid, it harasses the user with message boxes until they fix it.
void MyDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Text(pDX, IDC_EDIT_FOO, foo);
DDV_MinMaxFloat(pDX, foo, 0.001f, 300.0f);
}
I was able to do this by writing custom DDX_ handlers. The application I worked on used a custom control (MCReal derived from CEdit) that would only accept decimal values between an acceptable range defined in the control. When the user entered a non-decimal value, or, a value outside of the range, the code would pop up a custom message and revert the value entered into the dialog field.
This was accomplished by creating a custom control and a custom validation handler. Here’s what the DDX_ routine looked like:
void AFXAPI_EXPORT DDX_ProcessEditReal(CDataExchange* pDX, int nIDC, MCReal& mcr)
{
// prepare edit control
HWND hWndCtrl = pDX->PrepareEditCtrl(nIDC);
// does control exist yet?
if (!IsWindow(mcr.m_hWnd))
{
// subclass the control
if (!mcr.SubclassWindow(hWndCtrl))
{
ASSERT(false);
// possibly trying to subclass twice?
AfxThrowNotSupportedException();
}
return;
}
if (!ValidateMCRealCtrl (mcr, pDX->m_pDlgWnd, (pDX->m_bSaveAndValidate == TRUE)))
{
pDX->Fail ();
}
}
I used the standard DDX_ routines as a starting point to write a custom version. The real work is done in ValidateMCRealCtrl():
bool ValidateMCRealCtrl (MCReal &mcRealCtrl, CWnd *pParentWnd, bool bSaveAndValidate)
{
CString ctext;
double val = 0.0, r = 0.0;
double unit_factor = 0.0;
bool bDmsrg = false;
bool rc = false;
bool ret;
...
if (bSaveAndValidate) // Move from dialog to data
{
if (pParentWnd != nullptr && mcRealCtrl.CancelButtonClicked (pParentWnd))
{
return true;
}
if (!mcRealCtrl.IsWindowEnabled () || !mcRealCtrl.IsWindowVisible ())
{
return true;; // don't update if not enabled
}
mcRealCtrl.GetWindowText (ctext);
...
// base field validation.
ret = mcRealCtrl.Validate ();
if (!ret)
{
make_mcreal_str (r, ctext.GetBuffer (mcRealCtrl.maxlen), mcRealCtrl.maxlen, prec, mcRealCtrl.add_plus,
mcRealCtrl.m_strip_trailing == TRUE);
ctext.ReleaseBuffer ();
InvalidRealField (mcRealCtrl); // Bad value
return false; // Reset Focus
}
...
ctext.ReleaseBuffer ();
mcRealCtrl.SetWindowText (ctext);
}
else // Move from data to dialog
{
if (mcRealCtrl.angle) // If angle field...
{
val = mcRealCtrl.value * R2D; // Convert to degrees
}
else
{
val = mcRealCtrl.value; // Use data value
}
make_mcreal_str (val, ctext.GetBuffer (mcRealCtrl.maxlen), mcRealCtrl.maxlen, prec, mcRealCtrl.add_plus,
mcRealCtrl.m_strip_trailing == TRUE);
ctext.ReleaseBuffer ();
mcRealCtrl.SetWindowText (ctext);
mcRealCtrl.SetLimitText (mcRealCtrl.maxlen);
}
...
return true;
}
(Note: I've replaced code that does not pertain to your question with "...")
The work to revert the field value occurs in InvalidRealField (). That code displays a pop up message and uses the previous value of the field (saved within the actual MCReal control class), before it was changed, to revert the value.
This framework was not written specifically to revert incorrect dialog field values. It provides much more than that since the control class provides some extra capabilities. However, having the control defined in a custom class allowed me to provide custom validation.

How to get notification for keydown for CMFCRibbonComboBox?

I have CMFCRibbonComboBox on ribonbar and I want when that user press on a key open droplist and select Item acurding to chars that press by user.
For this purpose I want to get notification for keydown.
How can I to do it?
Thanks
I asked a very similar question on MSDN here and eventually solved it myself with the following hack;
Save a local copy of C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\atlmfc\src\mfc\afxribbonedit.cpp to your project
In BOOL CMFCRibbonRichEditCtrl::PreTranslateMessage(MSG* pMsg) replace this
case VK_DOWN:
if (m_edit.m_bHasDropDownList && !m_edit.IsDroppedDown())
{
m_edit.DropDownList();
return TRUE;
}
with this
case VK_DOWN:
if (m_edit.m_bHasDropDownList && !m_edit.IsDroppedDown())
{
m_edit.DropDownList();
CMFCRibbonBaseElement* pRibbonBaseElement = m_edit.GetDroppedDown();
if (pRibbonBaseElement && (pRibbonBaseElement->IsKindOf(RUNTIME_CLASS(CMFCRibbonComboBox))))
{
CString str;
GetWindowText(str);
CMFCRibbonComboBox *pCombo = (CMFCRibbonComboBox*)pRibbonBaseElement;
int ItemNo = -1;
for (int i = 0; i < pCombo->GetCount(); i++)
{
CString ItemText = pCombo->GetItem(i);
if (ItemText.Left(str.GetLength()).CompareNoCase(str) == 0)
{
ItemNo = i;
break;
}
}
if (ItemNo != -1)
{
pCombo->OnSelectItem(ItemNo);
// Draw and redraw dropdown for selection to show
m_edit.DropDownList();
m_edit.DropDownList();
}
}
return TRUE;
}
For drop lists (as opposed to drop downs) you can similarly hand WM_CHAR to do a first letter search based on the next item after the current position. Note that the above hack would need to be checked against any future updates to the ribbon library and should be dumped once it has been properly implemented in the library.

Differentiate between user click and SetChecked() in CListCtrl

I have a CListCtrl with checkboxes that I need to enable or disable based on some external factor. However, when I have more items in the list that can be displayed I cannot use EnableWindow(FALSE) on the control as it also disables the scrollbar.
So, I have searched and came up with the following code in the message map:
ON_NOTIFY(LVN_ITEMCHANGED, IDC_CHECKBOX_LIST, OnCheckboxChanged)
The callback function is implemented as:
void CUserPropertiesDialog::OnCheckboxChanged(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*) pNMHDR;
LVHITTESTINFO hitInfo;
hitInfo.pt = pNMListView->ptAction;
int nItem = m_checkBoxList.HitTest(&hitInfo);
if (hitInfo.flags != LVHT_ONITEMSTATEICON) return;
std::string groupName = static_cast<LPCTSTR>(m_checkBoxList.GetItemText(nItem, 0));
if (!CCharmUserAdminGUIApp::getTheCharmUserAdminGUIApp().isAdministrator())
{
if (pNMListView->uChanged & LVIF_STATE)
{
if (((pNMListView->uNewState & INDEXTOSTATEIMAGEMASK(2)) != 0) && ((pNMListView->uOldState & INDEXTOSTATEIMAGEMASK(1)) != 0))
{
CH_INFO1("CUserPropertiesDialog::OnCheckboxChanged - CheckBox Now Selected", groupName);
}
else if (((pNMListView->uNewState & INDEXTOSTATEIMAGEMASK(1)) != 0) && ((pNMListView->uOldState & INDEXTOSTATEIMAGEMASK(2)) != 0))
{
CH_INFO1("CUserPropertiesDialog::OnCheckboxChanged - CheckBox Now Unselected", groupName);
}
}
}
}
The problem is that this function is called when a user clicks the checkbox (good!) but also when the SetChecked() function is called from code.
I had hoped the check on hitInfo.flags would enable me to tell the click and the function apart but this is not the case.
Is there, besides setting some global flag before/after the function call and use that in the callback, any other way to tell whether the click or the function call is used?
I use the same inmy program and I used a flag.
But I use LVN_ITEMCHANGING. With this message I can prevent any change.
I overwrote SetCheck (even it is not virtual) and set a flag before I Change the Status of a list box item. The internal OnItemChanging Routine sees the flag set and allows the Change. The flag is directly cleared after the return.
So if the same Action is done with the mouse the flag is not set and you Need to check in a different way.
Same when I am loading the box. I set the flag, so that all changes can pass through...

How to check all check boxes in form application programatically?

I want to check all checkboxes when click on the button. All object are in form application of visual studio 2010 c++. The point of problem is that every object (checkbox) has various name, CheckBox1, CheckBox2, ... I make UnicodeString with value "CheckBox", and int value that begin with 1, and put it together in third variable to find object, and that's work, but don't have a clue how to check all those boxes, please help.
Windows 7, 64, Visual studio 2010(c++) or c++ builder 2010
I did something similar for another component, this is how I did using C++ Builder.
for (int i = 0; i < this->ComponentCount; i++)
{
TCheckBox *TempCheckBox = dynamic_cast<TCheckBox *>(this->Components[i]);
if (TempCheckBox)
{
TempCheckBox->Checked = true;
}
}
This will iterate through all the components on your form, if the component is a TCheckBox it will be checked.
Why dont you add everything to a vector containing checkboxes, and then iterate through them all when necessary? This will allow you to reference each checkbox individually, but yet all at once.
cliext::vector<System::Windows::Forms::CheckBox^> items;
items.push_back(checkbox1);
.
.
.
items.push_back(checkboxN);
It is important that you also include
#include <cliext/vector>
due to the fact that the normal vector in the standard library is currently unable to support this control.
In C++Builder, you can place all of your TCheckBox* pointers into an array or std::vector, which you can then loop through when needed, eg:
TCheckBox* cb[10];
__fastcall TForm1::TForm1(TComponent *Owner)
: TForm(Owner)
{
cb[0] = CheckBox1;
cb[1] = CheckBox2;
...
cb[9] = CheckBox10;
}
void __fastcall TForm1::Button1Click(TObject *Sender)
{
for (int i = 0; i < 10; ++i)
cb[i]->Checked = true;
}
If you have a lot of checkboxes and do not want to fill in the entire array by hand, you can use a loop instead:
__fastcall TForm1::TForm1(TComponent *Owner)
: TForm(Owner)
{
for (int i = 0; i < 10; ++i)
cb[i] = (TCheckBox*) FindComponent("CheckBox" + IntToStr(i+1));
}

how to write a function Click() for dynamic created button?

Trying to write a simple VCL program for educating purposes (dynamicly created forms, controls etc). Have such a sample code:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TForm* formQuiz = new TForm(this);
formQuiz->BorderIcons = TBorderIcons() << biSystemMenu >> biMinimize >> biMaximize;
formQuiz->Position = TPosition::poDesktopCenter;
formQuiz->Width = 250;
formQuiz->Height = 250;
formQuiz->Visible = true;
TButton* btnDecToBin = new TButton(formQuiz);
btnDecToBin->Parent = formQuiz;
btnDecToBin->Left = 88;
btnDecToBin->Top = 28;
btnDecToBin->Caption = "Dec to Bin";
btnDecToBin->Visible = true;
}
I wonder how can i write a function for dynamic created button, so it would be called when the button is clicked. In this example i need a 'btnDecToBin->Click();' func but i don't know where should i place it.
Inside 'void __fastcall TForm1::Button1Click(TObject *Sender){}' ?
I will appreciate any input, some keywords for google too.
You could do two things, you could either create an action and associate it with the button, or you could make a function like so:
void __fastcall TForm1::DynButtonClick(TObject *Sender)
{
// Find out which button was pressed:
TButton *btn = dynamic_cast<TButton *>(Sender);
if (btn)
{
// Do action here with button (btn).
}
}
You bind it to the button instance by setting the OnClick property btnDecToBin->OnClick = DynButtonClick please note that the function is inside the form Form1. This will work due to the nature of closures (compiler specific addition). The problem comes if you delete Form1 before formQuiz without removing the reference to the click event. In many ways it might be a more clean solution to use an Action in this case.
Edit: On other way to do this, if you have a standard layout for your quizforms, you could make a custom TQuizForm class inheriting from TForm. In this way you wouldn't have to bind the event each time you create the form.
all buttons have the normal "events" you just need to reference them to the method you will deal with the event.
example:
...
btnDecToBin->OnClick = &Test;
-- and add a additional method to .cpp
void __fastcall TForm1::Test(TObject *Sender)
{
TButton *btn = dynamic_cast<TButton *>(Sender);
if (btn->name == "your_button_name"){
// Do action here with button (btn).
}
}
and on .h
void __fastcall TForm1::Test(TObject *Sender);
reference the button either by the tag or name. I usually use a array of buttons that I create dynamically. ALWAYS sanity check your "sender" by casting it. There are other ways to hack info from the object but they are a path to heartache... LOL.