Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Разр-тка TDigitEdit = class(TCustomEdit), как побороть сво-воText [D7, WinXP]


ru_efim ©   (2006-04-04 12:10:00) 

Здравствуйте. Разрабатываю свой компонент на базе TcustomEdit для ввода десятичных чисел.
TDigitEdit = class(TCustomEdit)
Возникла следующая проблема. У TcustomEdit есть свойство Text унаследованное от TControl. Надо закрыть доступ к этому свойству. Чтобы оно не отображалось в инспекторе объектов, как сделать понятно, я его просто не публикую. Но в теле программы ни что не мешает мне вставить оператор DigitEdit1.Text:=  ‘1u2’ ;, вот этого и надо предотвратить. Например, если не публиковать в TDigitEdit свойство MaxLength(оно введено непосредственно в TcustomEdit), то DigitEdit1.MaxLength:= .. выполнить будет не возможно.
Или какой метод надо переопределить, чтобы перед изменением свойства Text проводилась проверка нового значения этого свойства, ну и естественно, если значение не прошло проверку, была возможность отменить изменения. Дайте совет, пожалуйста.


Юрий Зотов   (2006-04-05 20:37:00) [1]

> DimaBr   (05.04.06 20:02) [7]

Можно. И это правильно. Значит, разработчик потомка и не хотел, чтобы код попадал в Change - на то он и разработчик потомка. Component writer, а не прикладной батонокидатель. Но он обязан это сделать так, что уж если код не попадает в Change, то он не должен попадать туда никогда, каким бы образом к компоненту ни обращались и к какому бы типу его ни приводили. Иначе он полный чайник, а никакой не component writer.

А прикладному батонокидателю ничто не мешает написать в своей программе приведения типа а-ля
TCustomEdit(FindComponent(...)).Text := 'Вова'
и при этом он в полном праве ожидать корректного поведения компонента. А компонент вдруг поведет себя некорректно - и бедняга будет долго ломать голову над неожиданным багом, а потом скажет пару теплых слов в адрес разработчика компонента, который сделал поведение свойства зависимым от того, каким образом происходит обращение к этому свойству.. Приводим к TDigitEdit - работает, приводим к TСustomEdit - не работает. Налицо нарушение основополагающего принципа ООП.

Подчеркнутое и есть суть. Такого быть не должно.


DimaBr   (2006-04-05 20:02:00) [2]


> » TCustomEdit(MyEdit).Text := 'Вова';

ну, конечно я Вас уважаю, но можно в потомке и CNCommand(var Message: TWMCommand); message CN_COMMAND;
переопределить и в Change вообще не попадём.


Юрий Зотов   (2006-04-05 11:49:00) [3]

Перекрыть Change - и весь вопрос. Например, тупо "в лоб":

procedure TDigitEdit.Change;
var
 OldPos: integer;
begin
 OldPos := SelStart;
 try
   StrToInt64(Text);
   FOldText := Text;
   inherited
 except
   on E: EConvertError do
   begin
     Text := FOldText;
     SelStart := OldPos - 1
   end
   else
     raise
 end
end;
» Юрий Зотов: » FOldText - поле компонента.


DimaBr   (2006-04-05 11:45:00) [4]

Создайте своё свойство Text


property Text: string read GetText;

function TDigitEdit.GetText:string;
begin
 Result := inherited Text;
end;


оно будет только для чтения и присвоить ему не получится » Юрий Зотов: » TCustomEdit(MyEdit).Text := 'Вова';
Что получится?


icWasya   (2006-04-05 11:19:00) [5]

ну остаётся посмотреть исходники


procedure TControl.SetText(const Value: TCaption);
begin
 if GetText <> Value then SetTextBuf(PChar(Value));
end;

procedure TControl.SetTextBuf(Buffer: PChar);
begin
 Perform(WM_SETTEXT, 0, Longint(Buffer));
 Perform(CM_TEXTCHANGED, 0, 0);
end;

procedure TControl.DefaultHandler(var Message);
var
 P: PChar;
begin
 with TMessage(Message) do
   case Msg of
     WM_GETTEXT:
       begin
         if FText <> nil then P := FText else P := '';
         Result := StrLen(StrLCopy(PChar(LParam), P, WParam - 1));
       end;
     WM_GETTEXTLENGTH:
       if FText = nil then Result := 0 else Result := StrLen(FText);
     WM_SETTEXT:
       begin
         P := StrNew(PChar(LParam));
         StrDispose(FText);
         FText := P;
         SendDockNotification(Msg, WParam, LParam);
       end;
   end;
end;



и попытаться переопределить реакцию на WM_SETTEXT » Юрий Зотов: » Вот это уже другое дело, но есть и более простое решение - перекрыть Change.


ru_efim   (2006-04-04 23:22:00) [6]

Спасибо за советы. Добавить к стилю  ES_NUMBER поробую, возможно позволит освободится от ряда проверок. Но этого к сожалению не достаточно. На счет того что
"property Text write SetText; и в процедуре SetText делай нужные проверки", так что-то не получается. Мы заменяем TControl.Text, своим свойством ни как не связанным с наследуемым. Т.е. при присваивании нашему свойству Text значения, TControl.Text остается без изменений в то время как наш  компонент отображает именно TControl.Text. Метод TControl.SetText перегрузить тоже не получится т.к. это метод класса TControl, а в базовом классе его нет. Дак что же делать.


icWasya   (2006-04-04 16:18:00) [7]

пиши так
property Text write SetText;

и в процедуре SetText делай нужные проверки » Юрий Зотов: » Свойства невиртуальны, поэтому при изменении своего свойства Text метод SetText не вызовется. Кроме того, он статический да еще и приватный, так что перекрыть его тоже не получится. SetTextBuf тоже невиртуальный, перекрыть его тоже не выйдет.


MBo   (2006-04-04 12:48:00) [8]

А какие особые свойства должен иметь твой компонент? Если позволять вводить только числа - достаточно к стилю добавить ES_NUMBER


Наверх

Титульная страница Поиск, карта сайта Написать письмо