Доброго времени суток!
На главной форме 9 компонентов TEdit, для каждого из которых установлен програмный фильтр ввода, подобный представленному ниже. Проблема в том, что этот код повторяется в обработчике нажатия клавиши для каждого TEdit'а с изменением только имени компонента. Подскажите пожалуйста, возможно ли подобный код вынести в отдельную процедуру (желательно чтобы она находилась в отдельном модуле) - общую для всех TEdit'ов, а затем в обработчике только вызывать её?
procedure TForm.L_AKeyPress(Sender: TObject; var Key: Char);
var
vrPos, vrLength, vrSelStart: byte;
const
I: byte = 1;
begin
with Sender as TEdit do
begin
vrLength := Length(Text);
vrPos := Pos(',', Text);
vrSelStart := SelStart;
end;
case Key of
'0'..'9':
begin
if (vrPos > 0) and (vrLength - vrPos > I) and (vrSelStart >= vrPos)
then Key := #0;
if (vrLength=1) and (L_A.Text='0') and (vrSelStart=1)then Key:=#0;
if (vrPos=0) and (vrLength=3) and (vrSelStart=3) and (not (L_A.Text='100'))
then Key:=#0;
if (L_A.Text='100') and (vrSelStart=3) and (Key<>'0') then Key:=#0;
if (L_A.Text='1000')and (vrSelStart=4) then Key:=#0;
end;
',', '.':
begin
if (vrPos > 0) or (vrSelStart = 0) or (vrLength = 0) then
Key := #0
else
Key := #44;
if (L_A.Text='1000') then Key:=#0;
end;
#8: ;
else
Key := #0;
end;
end;
Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице. Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.
05-02-2009 00:31
Поскольку я с классами работать не умею, то мне очень интересно, можно ли такой фильтр реализовать через создание своего класса на основе TEdit или TCustomEdit.
Если уж создавать свой класс, то не наследника TEdit, а универсальный TValidator от TObject. Такое было сделано еще в приснопамятном TurboVision. Аналогичное решение есть и под Windows, только платное (конкретную ссылку сейчас не дам, поскольку не вспомню, а искать нет ни желания, ни времени).
>>> Поскольку я с классами работать не умею, то мне очень интересно, можно ли такой фильтр реализовать через создание своего класса на основе TEdit или TCustomEdit.
Можно. И гораздо легче, чем вы могли бы подумать... Но, думаю, лучше этого пока не делать. Причины - две:
1. К этому лучше переходить, уже имея некоторый опыт работы с классами.
2. В данном конкретном случае этого просто не нужно, только усложнит дело.
Достаточно часто более-менее объёмный код из обработчиков я выношу в отдельные пороцедуры, оставляя в самом обработчике только несколько строчек, примерно так, как сделали вы в приведённом коде. Это резко повышает читабельность. Однако я думаю, что вы это сделали по другой причине...
>>> А в обработчике события писал лишь
Эта фраза наводит на мысль о том, что вы видите выигрыш в в том, что весь код не придётся писать в каждом обработчике, а оставить в каждом обработчике только одну строчку. Вот здесь и есть главная тонкость, которую вы, на мой взгляд, всё-таки не уловили.
Обработчики (в том числе и OnKeyPress) - это указатели на методы, имеющие определённый набор параметров. Конкретно OnKeyPress объявлен так:
property OnKeyPress: TKeyPressEvent;
В свою очередь тип TKeyPressEvent - это указатель на процедуру, являющуюся методом (а не просто отдельную процедуру), имеющую такие параметры:
type TKeyPressEvent = procedure (Sender: TObject; var Key: Char) of object;
Вы можете всем нужным TEdit назначить в качестве обработчика указатель на одну-единственную процедуру. И вот тут для определения того, от кого пришёл вызов, в дело и вступает параметр Sender...
Подробнее об этом почитайте мои ответы на »вопрос КС №50218«
Если вам понадобится фунционал процедуры Filter в других модулях, то логично будет просто вынести её в какой-нибудь модуль, где вы складируете полезные процедуры, а в нужных формах создавать один обработчик с одной строчкой и назначать его нужным элементам этой формы. Такой вариант гораздо проще и удобнее, чем писать отдельный класс...
P.S. Хотя язык и позволяет не указывать список параметров процедур и функций в разделе реализации, всё-таки этой возможностью лучше не пользоваться, поскольку читабельность кода резко ухудшается.
Спасибо за ваши ответы! Наверно это они меня надоумили.
Решил этот вопрос так:
unit ...;
interface
procedure Filter(Sender: TObject; var Key: Char);
implementation
uses MainForm, StdCtrls;
procedure Filter;
const
I: byte = 1;
var
vrPos, vrLength, vrSelStart: byte;
begin
with Sender as TEdit do
begin
vrLength := Length(Text);
vrPos := Pos(',', Text);
vrSelStart := SelStart;
end;
case Key of
'0'..'9':
begin
if (vrPos > 0) and (vrLength - vrPos > I) and (vrSelStart >= vrPos) then Key := #0;
if (vrLength=1) and ((Sender as TEdit).Text='0') and (vrSelStart=1)then Key:=#0;
if (vrPos=0) and (vrLength=3) and (vrSelStart=3) and (not ((Sender as TEdit).Text='100'))
then Key:=#0;
if ((Sender as TEdit).Text='100') and (vrSelStart=3) and (Key<>'0') then Key:=#0;
if ((Sender as TEdit).Text='1000')and (vrSelStart=4) then Key:=#0;
end;
',', '.':
begin
if (vrPos > 0) or (vrSelStart = 0) or (vrLength = 0) then
Key := #0
else
Key := #44;
if ((Sender as TEdit).Text='1000') then Key:=#0;
end;
#8: ;
else
Key := #0;
end;
end;
end.
А в обработчике события писал лишь
procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
Filter(Edit1, Key);
end;
Поскольку я с классами работать не умею, то мне очень интересно, можно ли такой фильтр реализовать через создание своего класса на основе TEdit или TCustomEdit.
03-02-2009 11:12 | Комментарий к предыдущим ответам
with Sender as TEdit do - если вы используете возможности Sender, то все-таки неплохо бы было проверять, а действительно ли Sender - это TEdit и только потом делать приведение типов.
03-02-2009 10:38 | Вопрос к автору: запрос дополнительной информации
Судя по коду, работать с параметром Sender вы умеете. Непонятно, что же всё-таки вам мешает использовать Sender везде, не упоминая имя TEdit'а, и назначить всем своим TEdit'ам один обработчик.
Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Функция может не работать в некоторых версиях броузеров.