| Вскрываем ReadOnly property |
|
| Написал Snowy | |
| 10.02.2009 | |
|
При работе со сторонними компонентами и библиотеками, иногда может возникнуть несогласие с автором. В частности рассмотрим такой момент, когда автор класса сторонней библиотеки создал property, которую нельзя изменить, но нам очень хочется. Данный приём имеет ряд ограничений. Поэтому я не буду брать какой-то конкретный класс, а нарисую примитивный для примера. Допустим, есть такой класс: TStrikeCatsControl = class(TControl) private FCorrectValue: Integer; public constructor Create(AOwner: TComponent); override; published property CorrectValue: Integer read FCorrectValue; end; ... constructor TStrikeCatsControl.Create(AOwner: TComponent); begin inherited; FCorrectValue := Screen.DesktopWidth div 2; end;Вобщем какой-то сторонний компонент, у которого есть проперти CorrectValue. Автор контрола считает, что данное проперти не нуждается в записи, а должно вычисляться автоматом. Мы же считаем, что оно должно быть другим. Например Screen.Width div 2; Как быть? Изменить исходники компонента? Логично, но нехорошо. Да их может и не быть. Можно использовать нехитрый трюк. Допустим, мы бросили на форму данный контрол и хотим поменять ридонли проперти. Делается это просто, используя RTTI: PInteger(Integer(StrikeCatsControl1) + (Integer(GetPropInfo(TStrikeCatsControl, 'CorrectValue').GetProc) and $00FFFFFF))^ := Screen.Width div 2;Здесь StrikeCatsControl1 - имя нашего контрола, TStrikeCatsControl - имя класса. Используя RTTI, мы просто лезем в память и меняем значение FCorrectValue. Теперь эта проперти будет возвращать определённое нами значение. Теперь об ограничениях:
TStrikeCatsControl = class(TControl) private FCorrectValue: Integer; public constructor Create(AOwner: TComponent); override; property CorrectValue: Integer read FCorrectValue; end;Это нам не сильно помешает. Просто создаём наследника, в котором перемещаем эту property в published: TMyStrikeCatsControl = class(TStrikeCatsControl) published property CorrectValue; end;Всё. Теперь мы имеем RTTI для этого property. Немного изменится строка присвоения: PInteger(Integer(StrikeCatsControl1) + (Integer(GetPropInfo(TMyStrikeCatsControl, 'CorrectValue').GetProc) and $00FFFFFF))^ := Screen.Width div 2;Просто заменим имя класса - RTTI нужно брать из наследника, ибо в родителе его нет. Вопросы оставляйте в комментариях, ибо чувствую, что изложил не очень доступно. Добавлено Первое ограничение можно обойти также, как и третье, если поставить перед объявлением класса-наследника директиву {$M+} |
| След. > |
|---|

