delphic++builderc++builder-xe8

TStringGrid Input Validation to permit only numbers, decimals, and commas on C++ Builder XE8


This question is an extension of another question:

TEdit Input Validation on C++ Builder XE8

I have an editable TStringGrid. I only want the user to type numbers and a maximum of one decimal point or comma for each cell in the grid.

From the above link, I understand how to permit only certain keys, but not how to keep track of how many times a certain key-value already exists in the given cell.

From the above link, I have this:

void __fastcall TSetDataForm::ProbabilityGridKeyPress(TObject *Sender, System::WideChar &Key)
{
    if( Key == VK_BACK )
        return;

    if( (Key < L'0') || (Key > L'9') )
    {
        ShowMessage("Please enter numerals only");
        Key = 0;
    }
}

How do I allow '.' or ',' but only once?


Solution

  • I would suggest using TryStrToFloat() to validate the input, then there is no question whether the user is entering a valid decimal string or not. You would just need to handle the extra cases where:

    For example:

    class TStringGridAccess : public TStringGrid
    {
    public:
        __property InplaceEditor;
    };
    
    void __fastcall TSetDataForm::ProbabilityGridKeyPress(TObject *Sender, System::WideChar &Key)
    {
        switch (Key)
        {
            case 3: // Ctrl-C
            case 8: // Backspace
                return;
    
            case 22: // Ctrl-V
            {
                Key = 0;
    
                TInplaceEdit *Editor = ((TStringGridAccess*)ProbabilityGrid)->InplaceEditor;
    
                String SaveCellText = ProbabilityGrid->Cells[ProbabilityGrid->Col][ProbabilityGrid->Row];
    
                String SaveEditText = Editor->Text;
                int SaveSelStart = Editor->SelStart;
                int SaveSelLen = Editor->SelLength;
    
                Editor->Perform(WM_PASTE, 0, 0);
    
                TFormatSettings fmt = TFormatSettings::Create();
                fmt.DecimalSeparator = _D('.');
    
                double value;
                if (TryStrToFloat(Editor->Text, value, fmt))
                    return;
    
                ProbabilityGrid->Cells[ProbabilityGrid->Col][ProbabilityGrid->Row] = SaveCellText;
    
                Editor->Text = SaveEditText;
                Editor->SelStart = SaveSelStart;
                Editor->SelLength = SaveSelLen;
    
                break;
            }
    
            case _D('0'):
            case _D('1'):
            case _D('2'):
            case _D('3'):
            case _D('4'):
            case _D('5'):
            case _D('6'):
            case _D('7'):
            case _D('8'):
            case _D('9'):
            case _D('.'):
            {
                TInplaceEdit *Editor = ((TStringGridAccess*)ProbabilityGrid)->InplaceEditor;
    
                String str = Editor->Text;
                int idx = Editor->SelStart;
                int len = Editor->SelLength;
    
                String str2 = str.SubString(1, idx) + Key + str.SubString(1+idx+len, MaxInt);
    
                TFormatSettings fmt = TFormatSettings::Create();
                fmt.DecimalSeparator = _D('.');
    
                double value;
                if (TryStrToFloat(str2, value, fmt))
                    return;
    
                break;
            }
        }
    
        ShowMessage(_D("Please enter decimals only"));
        Key = 0;
    }