C++Builder
  Начало   Форум   Помощь Войти Регистрация  
Страниц: [1]   Вниз
  Печать  
Автор Тема: Ввод в StringGrid данных по маске в зависимости от ячейки.[РЕШЕНО]  (Прочитано 8595 раз)
Nikita
Участник


Сказали спасибо: +6/-1
Offline

Сообщений: 476


« : 02 Февраль 2013, 21:18:46 »

Приветствую всех.

На форме имееcтя StringGrid, в поля которой вводятся цифры. Некоторые цифры дробные, поэтому кроме цифр бывают еще и запятые. Чтобы пользователь не ввёл в поля других символов, я на событии OnGetEditMask моей таблицы StringGrid устанавливаю маски вида:

Код
if ((ACol==1)&&(ARow==0)) Value="00,0";
if ((ACol==2)&&(ARow==0)) Value="00,00";
if ((ACol==8)&&(ARow==0)) Value="0000";

Но вот незадача, при вводе данных 1,23 например, в ячейку с маской "00,00", пользователь вводит сначала цифру 1, запятая при этом уже присутствует и её вводить не надо, и далее вводит цифры 2 и 3. Но в ячейке получается 1(пробел),23 то есть между цифрой 1 и запятой присутствует пробел. Можно конечно, вводить 01,23 но это пользователям не объяснить. И получается ситуация, когда я пытаюсь перевести строку 1(пробел),23 в число функцией StrToFloat выскакивает исключение. потому что в строке между числами присутствует пробел.
Сажал на событие OnKeyPress функцию StringReplace которая должна заменять пробелы на "". Но ничего не получается.

Подскажите как справиться с этой проблемой??
« Последнее редактирование: 06 Февраль 2013, 19:08:34 от Nikita » Записан
POV
Участник


Сказали спасибо: +107/-7
Offline

Сообщений: 640


« Ответ #1 : 02 Февраль 2013, 21:35:49 »

Вариантов форматированного ввода мильён.. Я частенько использую проверку вводимого (по OnKeyPress) по TryFloatToStr - если не получается корректно, то последний вводимый Key обнуляю.
Записан
Nikita
Участник


Сказали спасибо: +6/-1
Offline

Сообщений: 476


« Ответ #2 : 02 Февраль 2013, 21:57:28 »

Я частенько использую проверку вводимого (по OnKeyPress) по TryFloatToStr

Мне из строки в цифру надо. К тому событие OnKeyPress одно на всю таблицу, а данные в ячейках разные
например по маскам:

Код
Value="#00";
Value="0000,0";
Value="0000";
Value="0,000";
Value="00";
« Последнее редактирование: 02 Февраль 2013, 22:03:04 от Nikita » Записан
S0mbre
Глобальный модератор


Сказали спасибо: +1113/-22
Offline

Сообщений: 2132

S0mbre


« Ответ #3 : 03 Февраль 2013, 10:50:55 »

Можно, например в обработчике OnKeyDown разрешать ввод только цифр и разделителя:
Код
void __fastcall TForm1::Edit1KeyDown(TObject *Sender, WORD &Key, TShiftState Shift)
{
  if(!((Key>='0' && Key<='9') || (Key==FormatSettings.DecimalSeparator))) Key = 0;
}
 
Записан
POV
Участник


Сказали спасибо: +107/-7
Offline

Сообщений: 640


« Ответ #4 : 03 Февраль 2013, 11:02:05 »

Можно, например в обработчике OnKeyDown разрешать ввод только цифр и разделителя:
Код
void __fastcall TForm1::Edit1KeyDown(TObject *Sender, WORD &Key, TShiftState Shift)
{
  if(!((Key>='0' && Key<='9') || (Key==FormatSettings.DecimalSeparator))) Key = 0;
}
 

Самый правильный и очевидный код. Но.. никто не помешает вести хоть 10 запятых. Я потому про TryStrToFloat и упомянул.
Да и вопрошающему надо бы помнить по возможность вставки из буфера. Впрочем, тут уже TryStrToFloat по OnKeyPress не поможет
Записан
S0mbre
Глобальный модератор


Сказали спасибо: +1113/-22
Offline

Сообщений: 2132

S0mbre


« Ответ #5 : 04 Февраль 2013, 08:08:23 »

Можно, например в обработчике OnKeyDown разрешать ввод только цифр и разделителя:
Код
void __fastcall TForm1::Edit1KeyDown(TObject *Sender, WORD &Key, TShiftState Shift)
{
  if(!((Key>='0' && Key<='9') || (Key==FormatSettings.DecimalSeparator))) Key = 0;
}
 

Самый правильный и очевидный код. Но.. никто не помешает вести хоть 10 запятых. Я потому про TryStrToFloat и упомянул.
Да и вопрошающему надо бы помнить по возможность вставки из буфера. Впрочем, тут уже TryStrToFloat по OnKeyPress не поможет

Это верно. Поможет OnChange. Что касается 10 запятых... что ж, дополнительная проверка нужна
Код
void __fastcall TForm1::Edit1Change(TObject *Sender)
{
TEdit* Edit = dynamic_cast<TEdit*>(Sender);
if(!Edit) return;  
 
String val(Edit->Text);
if(val.IsEmpty()) return;
 
bool Separator(false);
for(int i=1; i<=val.Length(); i++) {
if(val[i]==FormatSettings.DecimalSeparator) {
if(Separator) {val.Delete(i); --i;}
else Separator = true;
}
else if(!(val[i]>='0' && val[i]<='9'))
{ val.Delete(i); --i; }
}
Edit->Text = val;
}
 
« Последнее редактирование: 04 Февраль 2013, 08:17:30 от S0mbre » Записан
Nikita
Участник


Сказали спасибо: +6/-1
Offline

Сообщений: 476


« Ответ #6 : 04 Февраль 2013, 19:17:11 »

Ребята, у меня не поле Edit у меня таблица.

На событии таблицы KeyPress повесил следующий код:

Код
  TFormatSettings FormatSettings;
 FormatSettings.DecimalSeparator=',';
 
 if(Key==VK_RETURN)
  {
  if(StringGrid1->Col<(StringGrid1->ColCount-1)) {StringGrid1->Col++;}
 else StringGrid1->Col=0;
  }
 
 if(!isdigit(Key)&&(Key != VK_BACK)&&(Key!=VK_RETURN)&&(Key!=FormatSettings.DecimalSeparator))
  {
Key = 0x00;
Application->MessageBoxA(L"Вводите только цифры и знак запятой.",L"Ошибка ввода данных",MB_ICONINFORMATION);
  }

Теперь в любом поле таблицы можно вводить только цифры, запятую, BackSpace и Enter. Но никто не мешает пользователю ввести две запятые подряд, а также мне необходимо кроме этого в зависимости от номера столбца и строки проверить маску на ячейку, то есть, например, чтобы в некоторой ячейке можно было ввести число вида 00,0

Кодом
Код
   TStringGrid* StringGrid = dynamic_cast<TStringGrid*>(Sender);
if(!StringGrid) return;
 
  String var=StringGrid->Cells[StringGrid->Col][StringGrid->Row];
 
  if ((StringGrid->Col==1)&&(StringGrid->Row==0)) ...

я могу проверить в той ли ячейке происходило редактирование, и проверить сколько введено запятых и прочее, только не пойму на какое событие вешать этот код. Чтобы не на каждый вводимый символ срабатывал этот код а только на закончившееся редактирование или когда нужная ячейка теряет фокус. Как это сделать?

Если по клавише Enter перевели фокус, то это еще можно отследить, а если мышкой пользователь перевёл фокус на другую ячейку таблицы или закончил ввод в таблице и перешёл на другую. То тут уже непонятно как делать. 
« Последнее редактирование: 04 Февраль 2013, 19:36:04 от Nikita » Записан
volvo877
Глобальный модератор


Сказали спасибо: +736/-1
Offline

Сообщений: 891


« Ответ #7 : 05 Февраль 2013, 01:24:52 »

Если в обработчике OnSetEditText значение StringGrid->EditorMode = false, значит, пользователь только что закончил редактирование ячейки (и либо ушел на другую ячейку, либо вообще вышел из грида). Это то, что тебе нужно...
Записан
Nikita
Участник


Сказали спасибо: +6/-1
Offline

Сообщений: 476


« Ответ #8 : 05 Февраль 2013, 11:30:31 »

Если в обработчике OnSetEditText значение StringGrid->EditorMode = false, значит, пользователь только что закончил редактирование ячейки (и либо ушел на другую ячейку, либо вообще вышел из грида). Это то, что тебе нужно...

Попробовал этот код. Событие происходит если уйти с таблица совсем или по нажатию клавишы Enter сменяется ячейка. Но событие не происходит если мышкой перейти на другую ячейку таблицы и начать ввод данных там.
Это в принципе приемлимо.

Теперь у меня вопрос. Если какая нибудь функция которая может проверить введённые данные на соответствие маски, например как на событии OnGetEditMask? Например, в первой ячейке мне нужно число вида 00,0 во второй ячейке 00,000, в третьей вида #00,00. Инерисует не принадлежность числа к integer или float , а ограничение по количеству цифр до и после запятой, а так же кое где наличие знака - (минус)
« Последнее редактирование: 05 Февраль 2013, 11:40:33 от Nikita » Записан
volvo877
Глобальный модератор


Сказали спасибо: +736/-1
Offline

Сообщений: 891


« Ответ #9 : 05 Февраль 2013, 12:23:08 »

Событие происходит если уйти с таблица совсем или по нажатию клавишы Enter сменяется ячейка. Но событие не происходит если мышкой перейти на другую ячейку таблицы и начать ввод данных там.
Вот эту тему почитай: https://cbuilder.ru/index.php/topic,8899.0.html
Записан
Nikita
Участник


Сказали спасибо: +6/-1
Offline

Сообщений: 476


« Ответ #10 : 05 Февраль 2013, 12:43:05 »

Вот эту тему почитай: https://cbuilder.ru/index.php/topic,8899.0.html
Проблема смены ячейки любым способом решена кодом:

Код
void __fastcall TForm1::StringGrid1SetEditText(TObject *Sender, int ACol, int ARow,
 const UnicodeString Value)
{
FEdited = true;
if(StringGrid1->EditorMode==false)
{
ShowMessage("OnSetEditText -> Finished");
FEdited = false;
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::StringGrid1SelectCell(TObject *Sender, int ACol, int ARow,
         bool &CanSelect)
{
if(FEdited)
{
ShowMessage("OnSelectCell -> Finished");
FEdited = false;
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::StringGrid1Exit(TObject *Sender)
{
if(FEdited && !StringGrid1->EditorMode)
{
ShowMessage("OnExit -> Finished");
FEdited = false;
}
}

где bool  FEdited;  объявлен в private класса TForm1

Как теперь решить проблему проверки чисел по маскам?
Записан
Nikita
Участник


Сказали спасибо: +6/-1
Offline

Сообщений: 476


« Ответ #11 : 06 Февраль 2013, 19:07:13 »

Проблему по маскам решил следующим способом.

При смене ячейки или уход с таблицы нужно обработать следующий код:

Код
TStringGrid* StringGrid = dynamic_cast<TStringGrid*>(Sender);
if(!StringGrid) return;
 
 
String value=StringGrid->Cells[StringGrid->Col][StringGrid->Row];
float x=0;
if(TryStrToFloat(value,x))
{
 
if(StringGrid->Col==1)  // маска "00,0" / для второго столбца ячейки
   if(!TextCheck00_0(value)){Application->MessageBoxA(L"Данные не корректны (формат ячейки 00,0)",L"Ошибка ввода     данных",MB_ICONINFORMATION); StringGrid->Cells[StringGrid->Col][StringGrid->Row]="";}
 
...//далее по аналогии
 
}else { //если ошибка
 Application->MessageBoxA(L"Вводимые данные не корректны",L"Ошибка ввода данных",MB_ICONINFORMATION);
 StringGrid->Cells[StringGrid->Col][StringGrid->Row]="";
  }

//где функция TextCheck00_0

Код
bool TForm1::TextCheck00_0(String value)
{
//если соответствует маске то возвращает истину
bool ms1=false,ms2=false,ms3=false,ms4=false,ms5=false;
TMask *mask0 = new TMask("[0-9]");
TMask *mask0_0 = new TMask("[0-9],[0-9]");
TMask *mask00 = new TMask("[0-9][0-9]");
TMask *mask00_0 = new TMask("[0-9][0-9],[0-9]");
TMask *mask0_00 = new TMask("[0-9],[0-9][0-9]");
 
 if(mask0->Matches(value))   ms1=true;
 if(mask0_0->Matches(value)) ms2=true;
 if(mask00->Matches(value))  ms3=true;
 if(mask00_0->Matches(value))ms4=true;
 if(mask0_00->Matches(value))ms5=true;
 
delete mask0;
delete mask0_0;
delete mask00;
delete mask00_0;
delete mask0_00;
 
return (ms1|ms2|ms3|ms4|ms5);
}

Кроме того, как писалось выше, в таблицу нельзя вводить символы отличные от цифр, знака запятой, забой и ввод.

И так по аналогии можно сделать любую маску на любую ячейку таблицы, с буфера обмена тоже ничего не вставляется.

Проблема решена. Всем спасибо.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  




....

Powered by SMF 1.1.21 | SMF © 2025, Simple Machines
Страница сгенерирована за 0.196 секунд. Запросов: 21.