Краткое содержание : использовать промежуточный класс с переключением поведения во время выполнения.
Хотя @kobik использует Delphi 5 и не может делать то, что я описываю ниже, этот ответ раскрываетсяподдерживаемый способ изменить VMT экземпляра, используя TVirtualMethodInterceptor
.Комментарии Мейсона вдохновили меня на написание этого.
procedure MakeSuperImageList(ImageList: TImageList);
var
vmi: TVirtualMethodInterceptor;
begin
vmi := TVirtualMethodInterceptor.Create(ImageList.ClassType);
try
vmi.OnBefore := procedure(Instance: TObject; Method: TRttiMethod;
const Args: TArray<TValue>; out DoInvoke: Boolean; out Result: TValue)
var
Icon: TIcon;
Canvas: TCanvas;
Index: Integer;
X, Y: Integer;
begin
if Method.Name<>'DoDraw' then
exit;
DoInvoke := False;//don't call TImageList.DoDraw
Index := Args[0].AsInteger;
Canvas := Args[1].AsType<TCanvas>;
X := Args[2].AsInteger;
Y := Args[3].AsInteger;
Icon := TIcon.Create;
try
ImageList.GetIcon(Index, Icon);
Canvas.Draw(X, Y, Icon);
finally
Icon.Free;
end;
end;
vmi.Proxify(ImageList);
finally
vmi.Free;
end;
end;
Я только скомпилировал это в своей голове, так что, несомненно, потребуется отладка.Что-то подсказывает мне, что захват ImageList
может не работать, и в этом случае вам нужно будет написать Instance as TImageList
.
Если вы не используете решение на основе модификации VMT, вам придется создавать новые экземпляры (согласно Мэйсонупредложение).А это значит, что вам также придется изменять все ссылки на экземпляры списка изображений одновременно с созданием новых экземпляров.На мой взгляд, это исключает любое предлагаемое решение, основанное на создании экземпляров замещающих объектов.
Итак, я пришел к выводу, что для реализации предложенного решения в полной общности вам потребуется модификация VMT во время выполнения.И если у вас нет современного Delphi, который предоставляет такие средства поддерживаемым способом, вам нужно будет взломать VMT.
Теперь, изменение VMT, даже с перехватчиками виртуальных методов, довольно неприятно, по моемуПосмотреть.Я думаю, вы, вероятно, ошибаетесь.Я предлагаю использовать промежуточный класс (или другой метод подклассов) и переключать поведение во время выполнения с помощью свойства подкласса.
type
TImageList = class(ImgList.TImageList)
private
FIsSuper: Boolean;
protected
procedure DoDraw(Index: Integer; Canvas: TCanvas; X, Y: Integer;
Style: Cardinal; Enabled: Boolean = True); override;
public
property IsSuper: Boolean read FIsSuper write FIsSuper;
end;
TImageList.DoDraw(Index: Integer; Canvas: TCanvas; X, Y: Integer;
Style: Cardinal; Enabled: Boolean = True);
var
Icon: TIcon;
begin
if IsSuper then
begin
Icon := TIcon.Create;
try
Self.GetIcon(Index, Icon);
Canvas.Draw(X, Y, Icon);
finally
Icon.Free;
end;
end
else
inherited;
end;
....
procedure TForm1.Button1Click(Sender: TObject);
begin
ImageList2.IsSuper := True;
ImageList3.IsSuper := True;
end;