Числовой TEdit с использованием WinApi.
Необходимо, чтобы в TEdit пользователь мог ввести только цифры? Я часто встречаю различные решения данной задачи, которые в основном сводятся к обработке события OnKeyPress. Сегодня рассмотрим кардинально другой подход — изменение стиля TEdit с помощью WinApi.
Итак, как же чаще всего фильтруют? Этот способ я даже встречал в каких-то официальных исходниках-примерах от borland.
Суть метода состоит в том, чтобы обрабатывать событие OnKeyPress, проверять параметр Key, передаваемый обработчику. Это char, да. И если этот char — не разрешенный символ для ввода и не #8 (backspace, про него не стоит забывать), то установить тот же Key в #0. Таким образом, некавайные символы не получится ввести.
Вот из из множества возможных вариантов реализации:
procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char); begin if not(Key in ['0'..'9', #8]) then Key:=#0; end;
Здесь нам помогает оператор in, который проверяет наличие символа в указанном нами массиве (от нуля до девятки и backspace). С другим набором символов это, может быть, и наиболее правильный способ, но фильтрация ввода чисел в самом TEdit уже предусмотрена, нам надо только изменить его стиль, о чём далее.
Константы, начинающиеся на WS_ (от window style) являют собой константы стилей для объектов. Обязательно указываются при создании окон через различные winapi-функции. Наш TEdit WS_CHILD и WS_VISIBLE — дочерний и видимый. Также есть специальные константы только для Edit’ов, они начинаются на ES_. ES_NUMBER — нужный нам стиль. Подробнее про стили напишу когда-нибудь на блоге :)
Для изменения стилей в 32-хбитных windows была функция SetWindowLong, для совместимости с 64-хбитными была введена api функция SetWindowLongPtr.
SetWindowLongPtr(Edit1.Handle, GWL_STYLE, WS_CHILD or WS_VISIBLE or ES_NUMBER);
Если приведённый ниже код написать в FormCreate, то пользователь ничего не сможет ввести, кроме цифр, что и требовалось.
Да, функция SetWindowLongPtr, в отличие от SetWindowLong, отсутствует в delphi седьмой версии и ниже, если используешь, то надо импортировать из user32.dll.
Постовой:
dmitko.ru: Блог о python, django, javascript и многом другом.
(c) Всегда ваш crystalbit
В Delphi 2010 для у TEdit есть свойство NumbersOnly, которое делает то же самое. =)
В D2010 многие вещи значительно проще, но до сих пор многие разработчики работают в более ранних системах.
Я в более старой версии работаю. Зато это актуально для множества других языков, где нет NumbersOnly :)
а что мешает вам перейти на новую версию? привычка или любовь к старой?
Привычка скорее, да и не хочется тратить время на установку, учитывая то, что седьмая вполе устраивает
Пришлось подобным заниматься, когда писал программку для заполнения персональных данных. Чего только не пытались ввести! Сначала данные хранились в простом xml, так отдельные извращенцы лазали туда и правили руками то, что не получилось из программы — пришлось шифровать.
Что касается поля только с цифрами, то, если я не ошибаюсь, нужно еще сделать обработчик вставки в поле чтобы через правый клик мыши — вставить не обошли защиту
Хм, думал что если установить стиль через WinApi, то вставка будет фильтроваться. Сейчас проверил, действительно, можно обойти.
Спасибо за дополнение к посту :)
Установив стиль окна ES_NUMBER мы запрещаем вводить нецифровые символы с клавиатуры, однако их можно будет вставить из буфера обмена. Чтобы запретить и это нужно переопределить процедуру окна на свою:
Schnider, огромное спасибо, наглядно :)
Думаю что в таком случае будет всё таки проще использовать:
if not(Key in ['0'..'9', #8]) then Key:=#0;
Когда несколько вариантов, есть возможность поспорить :)
В таком случае всё равно вставку из буфера фильтровать нужно.
По мне так проще один раз поменять стиль Edit’а, чем фильтровать каждый символ через обработчик события.
А всегда пользовался только: onkeypress. :) И ничего — работает! Хотя как альтернатива, что бы запутать программиста — можно попробовать :)
Не сталкивался с такой задачей целенаправленного числового edit-a, и не думал что это реализуется на win api, вобщем покопошился в сети и нашел, может кому поможет — http://www.sql.ru/forum/actualthread.aspx?tid=509731&pg=2 (это не спам):-)
Все варианты, которые раскрыты там, или слишком мудрёные (на onChange имхо не совсем адекватно — надо парсить всю строку), или раскрыты в моём посте :) Спасибо за ссылку
Upd: В моем примере выше у функции MyWinProc нужно обязательно указать директиву stdcall иначе может быть AccessViolation
Спасибо, дополнил
спасибо, кокраз в вузе стали требовать что бы писали проги вообще без возможности вылета ошибки, а так можно исключить основную часть приводящую к из возникновению.
Да, способ полезный, однако пригодится он, разве что, в достаточно крупных проектах, коими будут пользоваться множество пользователей, которые далеко не всегда адекватны в том, что вводят ;)
А для простеньких программулек «OnKeyPress» более чем подойдёт.
Не скажи, иногда хочется всё сделать чисто, чтобы блестело :)
По-моему неудачное решение: ведь дробное число в такой эдит уже не введёшь…
смотря какие цели преследовать, да