Компонент Delphi Edit

Как ввести только числа




Уроки Delphi
  1.  Первая программа
  2.  Использование компонентов
  3.  События Delphi
  4.  Типы данных Delphi
  5.  Создание своих типов данных
  6.  Выражения и операторы
  7.  Работа с файлами в Delphi
  8.  Дополнительные формы
  9.  Подпрограммы в Delphi
  10. Исключительные ситуации
  11. Взаимодействие приложения с пользователем
  12. Указатели в Delphi
  13. Обзор компонентов
  14. Работа со строками
  15. Создание интерфейса
  16. Графика в Delphi
  17. Многопоточность в Delphi
  18. Динамическое создание
        компонентов
Поиск по сайту




 Это важно:
   Метод Application.ProcessMessages;

 Это полезно:
   Параметр Sender в обработчиках событий;










Бояться не надо



   

Программа на Delphi, запрещающая ввод нечисловых символов

   Программа состоит из двух процедур. Первая, работающая в обработчике события KeyPress компонента Edit, не допускает появления нежелательных символов, то есть любых, не равных цифре или символу-разделителю целой и дробной частей числа. Последний может быть равен точке или запятой, в зависимости от текущих настроек Windows. Поэтому используется встроенная в Delphi константа DecimalSeparator, содержащая нужный символ. Вторая процедура, базирующаяся на обработчике события KeyUp, приводит вводимое число к привычному, общеупотребительному виду. Например, не допускает появления числа, у которого символ-разделитель - первый из символов.


unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    procedure Edit1KeyPress(Sender: TObject; var Key: Char);
    procedure Edit1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{Процедура, запрещающая появление нежелательных символов в edit.
Если вводимый символ, код которого содержится в переменной Key, не содержится во множествах Digit или Separator, то переменной Key присваивается код "отсутствие символа", равный #0.
Для того чтобы раскладки клавиатуры не влияли на ввод символа-разделителя, производится анализ на символы, находящиеся на тех кнопках, где располагаются точка либо запятая. Нажатие этих кнопок приводит к вводу символа DecimalSeparator. Однако повторный ввод разделителя не допускается.}


procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
//Множество цифр, допустимых для ввода в edit:
const Digit: set of Char=['1'..'9', '0'];
//Множество символов, воспринимаемых как символ-разделитель:
  Separator: set of Char=['/', '.', ',', 'ю', 'Ю', 'б', 'Б'];
begin
with (Sender as TEdit) do
  begin
    if (Key in Separator)
     then Key:=DecimalSeparator //Delphi-константа типа Char, равная символу-разделителю Windows
     else
       if (not(Key in Digit))
       then Key:=#0;
    if ((Key=DecimalSeparator)and(pos(DecimalSeparator, Text)<>0))
      then Key:=#0;
  end;
end;

{Процедура, приводящая вводимое число к общеупотребительному виду. Для этого производится анализ на положение символа-разделителя (чтобы он был не первым либо последним), первый ноль перед символом, не равным символу-разделителю, завершающие нули в нецелом числе и т. д. Процедура также обеспечивает стирание введённых символов.}

procedure TForm1.Edit1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
var n: Integer;
    S: String;
begin
with (Sender as TEdit) do
  begin
    if pos(DecimalSeparator, Text)=1 then
      begin
        Text:='0'+Text;
        SelStart:=Length(Text);
      end;
    if (pos(DecimalSeparator, Text)<>Length(Text)) then
      if Text[Length(Text)]<>'0' then
        if FloatToStr(StrToFloat(Text))<>'0' then
          Text:=FloatToStr(StrToFloat(Text));
    if Key=8 then
      begin
        n:=SelStart;
        S:=Text;
        Delete(S, n, 1);
        Text:=S;
      end;
    SelStart:=Length(Text);
  end;
end;

end.





   Сначала положите на Форму компонент Edit. Затем, открыв вкладку Events в Инспекторе Объектов и дважды щёлкнув по обработчикам событий OnKeyPress и OnKeyUp компонента Edit, создайте заготовки обработчиков этих событий. Затем замените обработчики предлагаемыми процедурами - и ваш Edit сможет содержать только числа. Если у вас несколько компонентов, то достаточно создать тоько одну пару предлагаемых процедур, для одного, любого из них. К остальным их нужно подключить, выбрав в Инспекторе Объектов в качестве обработчиков соответствующих событий.

   Дополнительно можно обеспечить размещение числа у правого края Edit, как в калькуляторе Windows. Для этого сразу после

implementation

{$R *.dfm}

добавьте следующий код:

type
  TMEdit = class(TEdit)
  procedure CreateParams(var Params: TCreateParams); override;
  end;

{ TMEdit }

procedure TMEdit.CreateParams(var Params: TCreateParams);
begin
  inherited;
  Params.Style := Params.Style or ES_RIGHT;
end;

а также в обработчике события OnCreate Формы (если его нет - создайте!) добавьте строку

  PPointer(Edit1)^ := TMEdit;

Естественно, Edit1 замените на имя вашего компонента.


Delphi Edit           В начало урока          Delphi Memo  

Уроки Delphi начинающим



Вопросы и комментарии (31)      Решение задач в Delphi

Кирил, добавлено 19.01.11, 15:28:16 
Процедуру удаления символа из Edit можно осуществить намного проще с помощью Label-метки
if Key=#8 then goto Back;
в прицедуре Edit1.KeyPress
Автор, добавлено 19.01.11, 15:42:21 
Неожиданно... Надо будет попробовать, пока не совсем понял. Кирилл, привели бы процедуру целиком, я бы опубликовал с вашим авторством!
Кирил, добавлено 19.01.11, 16:21:04 

procedure TForm2.Edit4KeyPress(Sender: TObject; var Key: Char);
label Back;
Const
  Digit: set of Char=['1'..'9','0'];
  Separator: set of Char=[',','.','/', 'ю', 'Ю', 'б', 'Б'];
begin
  if (Key=#8)or(Key=#46) then goto Back;
  if (Key in Separator) then Key:=DecimalSeparator
  else if (not(Key in Digit)) then Key:=#0;
  if ((Key in Separator)and(pos(DecimalSeparator,Edit4.Text)<>0)) then Key:=#0;
Back:
if pos(DecimalSeparator,Edit4.Text)=1 then
  begin
  Edit4.Text:='0'+Edit4.Text;
  Edit4.SelStart:=Length(Edit4.Text);
  end;
end;
Вот как то так, все отлично работает(Поле ввода стоимости товара)
Кирил, добавлено 19.01.11, 16:23:57 
Да!, И БОЛЬШОЕ ВАМ СПАСИБО!!!
Я только учусь работать в Delphi, пользуюсь в основном вашим сайтом
есть еще электронная книга, тоже неплохая. Если надо могу скинуть.
Автор, добавлено 19.01.11, 17:02:34 
Кирилл, спасибо! Через пару дней сделаю поправку к статье, учитывающую ваш вариант. Справедливости ради замечу, что всё же лучше использовать условный оператор if() then/else, чем оператор go to, который считается "плохим тоном" в программировании.
Кирил, добавлено 19.01.11, 17:13:24 
В принципе можно и заменить (goto Back;) на begin, а Back на end;
а условие if на отрицание: if (not(Key=#8)or(Key=#46))
и будет красиво)))))
Автор, добавлено 19.01.11, 17:39:00 
Именно это я и имел в виду!
Ренат, добавлено 4.04.11, 14:32:56 
Круто! Ты очень помог!
Андрей, добавлено 24.10.11, 17:57:46 
Здравствуйте, у меня не получается использовать эти процедуры. Где их описать, чтобы использовать в других местах программы, и что указывать при обращении
Автор, добавлено 24.10.11, 18:57:52 
Вам просто нужно сопоставить эти процедуры вашим компонентам. В Инспекторе Объектов щелкните по соответствующим обработчикам.

Андрей, добавлено 31.10.11, 13:01:40 
А как проверять несколько компонентов?
Автор, добавлено 31.10.11, 15:59:04 
Если у вас несколько компонентов, принимающих только числа, нет смысла плодить эти процедуры для каждого. Достаточно этих. Естественно, нужно сопоставить их каждому компоненту, и заменить в каждой процедуре Edit1 на (Sender as TEdit) - вот так, в скобках. А лучше с помощью оператора with вынести это вообще за код, как показано в статье параметр Sender.
Андрей, добавлено 5.11.11, 16:19:38 
Большое спасибо за данный урок)))
НачинающийИПродолжающий, добавлено 30.11.11, 10:37:23 
Похоже я украду эту программку :) но с замечанием.
ввожу 000.123, должно быть 0.123, однако получается - 230.1
В тот момент, когда удаляются впереди стоящие нули, крсор остаетсяв начале строки. То есть, если пользователь не заметит и продолжит вводить цыфры, то они начиная со второй циыры после запятой будут печататься сначала, а именно перед первым нулем.
как же быть?
Автор, добавлено 30.11.11, 10:46:27 
Недочётец! Спасибо за находку. Но исправить проще простого - оператор

Edit1.SelStart:=n-1;

нужно вынести за end; То есть он не должен подчиняться условию. Проверяйте.
НачинающийИПродолжающий, добавлено 30.11.11, 11:05:47 
Спасибо за быстрый ответ!
Эту процедуру я немного изменил, т.к. воспользовался вариантом Кирилла для стирания введенных цифр. Вот что у меня:
procedure TfrmMain.edtSumSaleKeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if pos(DecimalSeparator, edtSumSale.Text)=1 then
  begin
  edtSumSale.Text:='0'+edtSumSale.Text;
  edtSumSale.SelStart:=Length(edtSumSale.Text);
  end;
  if (pos(DecimalSeparator, edtSumSale.Text)<>Length(edtSumSale.Text)) then
  if edtSumSale.Text[Length(edtSumSale.Text)]<>'0' then
  if FloatToStr(StrToFloat(edtSumSale.Text))<>'0' then
  edtSumSale.Text:=FloatToStr(StrToFloat(edtSumSale.Text));
  edtSumSale.SelStart:=Length(edtSumSale.Text); //ставлю курсор в конец поля ввода
end;
но этом случае, если двигать курсор влево (с помощью клавиши <-), он снова встает в конец :D
неуж-то придется вставлять еще и проверку на нажатие клавиш управления курсором?
Автор, добавлено 30.11.11, 11:24:08 
В общем, решение вот какое. Нужно оставить мою поправку после вашего первого замечания, и всё! Дело, думаю, в наличии самого курсора. Если бы его не было видно, никто бы и не замечал, куда там он сдвигается. Посмотрите на калькулятор Windows. Ввод идёт только в конец числа. Нужно исправить - стираем лишние символы.

Кстати, проверка на клавиши курсора не помогает, а добавляет проблем.

Надо посмотреть, нет ли способа убрать курсор с глаз долой.
Автор, добавлено 30.11.11, 11:49:26 
Поправка. Не

Edit1.SelStart:=n-1; //n не определено

а

Edit1.SelStart:=Length(Edit1.Text);

НачинающийИПродолжающий, добавлено 30.11.11, 11:54:32 
Вот мое решение проблемы:
procedure TfrmMain.edtSumSaleKeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if pos(DecimalSeparator, edtSumSale.Text)=1 then
  begin
  edtSumSale.Text:='0'+edtSumSale.Text;
  edtSumSale.SelStart:=Length(edtSumSale.Text);
  end;
  if (pos(DecimalSeparator, edtSumSale.Text)<>Length(edtSumSale.Text)) then
  if edtSumSale.Text[Length(edtSumSale.Text)]<>'0' then
  if (FloatToStr(StrToFloat(edtSumSale.Text))<>'0') and
//если следующее условие не выполняется, то и изменять поле не резон, не спа
  (FloatToStr(StrToFloat(edtSumSale.Text))<>edtSumSale.Text)
  then
  begin
  edtSumSale.Text:=FloatToStr(StrToFloat(edtSumSale.Text));
  edtSumSale.SelStart:=Length(edtSumSale.Text);
  end;
end;
Автор, добавлено 30.11.11, 12:01:44 
И как теперь стирать???
НачинающийИПродолжающий, добавлено 30.11.11, 12:04:28 
как Кирилл:
procedure TfrmMain.edtSumSaleKeyPress(Sender: TObject; var Key: Char);
//Множество цифр для ввода
const Digit: set of Char=['1'..'9', '0'];
//Множество символов-разделителей
  Separator: set of Char=['/', '.', ',', 'ю', 'Ю', 'б', 'Б'];
begin
  if (not(Key=#8)or(Key=#46)) then //если не стирание символов
  begin
  if (Key in Separator) then Key:=DecimalSeparator
  else
  if (not(Key in Digit)) then Key:=#0;
  if ((Key in Separator) and (pos(DecimalSeparator,edtSumSale.Text)<>0))
  then Key:=#0;
  end;
  if pos(DecimalSeparator,edtSumSale.Text)=1 then
  begin
  edtSumSale.Text:='0'+edtSumSale.Text;
  edtSumSale.SelStart:=Length(edtSumSale.Text);
  end;
end;
Автор, добавлено 30.11.11, 12:20:02 
Или так - нужно добавить мой стирающий блок:

if Key=8 then
  begin
  n:=Edit1.SelStart;
  S:=Edit1.Text;
  Delete(S, n, 1);
  Edit1.Text:=S;
  Edit1.SelStart:=n-1;
  end;

 Вроде всё работает. Почему мне так больше нравится - мой обработчик KeyPress кратче. Ваш вариант KeyUp действительно решает проблему. С добавлением блока стирания.
НачинающийИПродолжающий, добавлено 30.11.11, 12:42:55 
кажется нашлась еще одна загвоздка ))) с дробями
ввожу 102,
затем стираю единичку
получается 02,
и так остается пока не ввести в конце какую либо цифру (кроме 0, т.к. получается 02,00)
а хотелось бы, чтобы 02, превратилось в 2, при уходе курсора из начала поля.
боюсь, что нет предела совершенству :)
Автор, добавлено 30.11.11, 13:22:36 
В общем, одна маета. А ведь чуть не исправил основной вариант. Оставляю как есть - с первой поправкой.
НачинающийИПродолжающий, добавлено 30.11.11, 14:28:30 
я вот такой костыль прикрутил на OnExit:

procedure TfrmMain.edtSumSaleExit(Sender: TObject);
var strSumSale: String;
begin
  edtSumSale.Text:=FloatToStr(StrToFloat(edtSumSale.Text));
end;

пусть хоть при выходе из поля поправит
а может еще чего придумается ;)
С наступающим, Автор!
Спасибо за сайт, за помощь, за виртуальное, но живое общение.
Виталий, добавлено 16.12.11, 16:24:28 
На мой взгляд вторая процедура только усложняет программу и интерпретация ",1" как "0,1" допустима. Тогда в первую процедуру надо только добавить условие
if Key<>#8 then
Тогда backspace работает и стирает не по одной цифре и из любого места числа.

Спасибо за статью и подробные комментарии :)
Руслан, добавлено 27.04.12, 20:08:21 
Доброго времени суток!Отличные програмки! Пожалуйста помогите, как использовать эти процедуры если у меня Едиты изначально не расположены на форме, а создаются программно (N-ое количество). Как для них установить такиеже "свойства"?

Автор, добавлено 27.04.12, 20:51:26 
Почитайте динамическое создание компонентов и параметр Sender, я там всё описал. Ну а если будут неясности, тогда пишите.
Павел, добавлено 20.03.14, 01:25:15 
Здравствуйте, уважаемый Автор!
Подскажите, пожалуйста, какую нагрузку несёт в себе выполнение условия
if Text <> '0' then
Text:=FloatToStr(StrToFloat(Text));
Павел, добавлено 20.03.14, 01:33:27 
Почему для удаления незначащих нулей не выполнить просто присваивание без условия?
Text:=FloatToStr(StrToFloat(Text));

P.S. ошибся в предыдущем комментарии должно быть:
if FloatToStr(StrToFloat(Text)) <> '0' then
Text:=FloatToStr(StrToFloat(Text));

И не понятно зачем два раза двойное преобразование
Автор, добавлено 20.03.14, 06:03:18 
Проект был сделан давно. Сейчас пробую, комментирование этого условия ничего вроде не меняет. Наверное, можно и без него.
Оставить комментарий:

Имя  

Текст комментария