Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Разбираемся с свойством Variant в Object Inspector в Embarcadero RAD Studio 12

Delphi , Синтаксис , Типы и Переменные

 

В процессе разработки приложений на Delphi иногда возникает необходимость использовать свойства типа Variant. Однако, как выяснилось, стандартный инспектор свойств (Object Inspector) в Embarcadero RAD Studio 12 не всегда корректно работает с этим типом данных. В этой статье мы рассмотрим проблему и предложим несколько решений для её устранения.

Описание проблемы

Вот пример определения компонента с свойством CheckedValue типа Variant:

TTestComponent = class(TComponent)
private
  FCheckedValue: Variant;
  function GetCheckedValue: Variant;
  function IsCheckedValueStored: Boolean;
  procedure SetCheckedValue(const Value: Variant);
  procedure CheckedValueChanged();
public
  constructor Create(AOwner: TComponent); override;
  destructor Destroy; override;
published
  property CheckedValue: Variant read GetCheckedValue write SetCheckedValue stored IsCheckedValueStored;
end;

Когда вы пытаетесь установить новое значение для этого свойства в режиме Design-Time, вы сталкиваетесь с ошибкой: «Could not convert variant». В выпадающем списке типов система не позволяет выбрать новый тип, и при попытке ввести новое значение появляется ошибка «Could not convert variant».

Причина проблемы

Проблема заключается в том, что стандартные редакторы свойств в режиме Design-Time не полностью поддерживают тип Variant. Это связано с тем, что Variant является динамическим типом данных, который может хранить значения различных типов, и стандартные редакторы не могут корректно обрабатывать такие динамические типы.

Решение проблемы

Для устранения этой проблемы можно внести небольшие изменения в метод SetCheckedValue и функцию .IsCheckedValueStored, чтобы убедиться, что типы Variant совпадают перед сравнением их значений. Также можно добавить обработку для строковых значений, чтобы убедиться, что они имеют правильный тип.

Вот исправленный код:

procedure TTestComponent.SetCheckedValue(const Value: Variant);
begin
  if (VarType(FCheckedValue) <> VarType(Value)) or // Добавляем проверку на совпадение типов
     (not VarSameValue(FCheckedValue, Value)) then
  begin
    FCheckedValue := Value;
    if VarType(FCheckedValue) = varString then
      FCheckedValue := VarToStr(Value); // Изменяем тип на varUString для строковых значений
    CheckedValueChanged();
  end;
end;

function TTestComponent.IsCheckedValueStored: Boolean;
begin
  Result := (VarType(FCheckedValue) <> varBoolean) or // Добавляем проверку на тип
            (not VarSameValue(FCheckedValue, True));
end;

Дополнительное решение: создание кастомного редактора свойств

Если стандартные редакторы свойств всё ещё не корректно обрабатывают свойство Variant, можно создать кастомный редактор свойств. Это позволит вам полностью контролировать процесс установки и отображения значений свойств.

Вот пример создания кастомного редактора свойств для типа Variant:

uses
  Variants, DesignIntf, DesignEditors, DesignConst;

{ TMyVariantTypeProperty }

const
  VarTypeNames: array[varEmpty..varInt64] of string = (
    'Unassigned', // varEmpty
    'Null',       // varNull
    'Smallint',   // varSmallint
    'Integer',    // varInteger
    'Single',     // varSingle
    'Double',     // varDouble
    'Currency',   // varCurrency
    'Date',       // varDate
    'OleStr',     // varOleStr
    '',           // varDispatch
    '',           // varError
    'Boolean',    // varBoolean
    '',           // varVariant
    '',           // varUnknown
    '',           // [varDecimal]
    '',           // [undefined]
    'Shortint',   // varShortInt
    'Byte',       // varByte
    'Word',       // varWord
    'LongWord',   // varLongWord
    'Int64');     // varInt64

type
  TMyVariantTypeProperty = class(TNestedProperty)
  public
    function AllEqual: Boolean; override;
    function GetAttributes: TPropertyAttributes; override;
    function GetName: string; override;
    function GetValue: string; override;
    procedure GetValues(Proc: TGetStrProc); override;
    procedure SetValue(const Value: string); override;
  end;

function TMyVariantTypeProperty.AllEqual: Boolean;
var
  i: Integer;
  V1, V2: Variant;
begin
  Result := False;
  if PropCount > 1 then
  begin
    V1 := GetVarValue;
    for i := 1 to PropCount - 1 do
    begin
      V2 := GetVarValueAt(i);
      if VarType(V1) <> VarType(V2) then Exit;
    end;
  end;
  Result := True;
end;

function TMyVariantTypeProperty.GetAttributes: TPropertyAttributes;
begin
  Result := [paMultiSelect, paValueList, paSortList];
end;

function TMyVariantTypeProperty.GetName: string;
begin
  Result := 'Type';
end;

function TMyVariantTypeProperty.GetValue: string;
begin
  case VarType(GetVarValue) and varTypeMask of
    Low(VarTypeNames)..High(VarTypeNames):
      Result := VarTypeNames[VarType(GetVarValue) and varTypeMask];
    varString, varUString: // Исправляем для строковых значений
      Result := SString;
  else
    Result := SUnknown;
  end;
end;

procedure TMyVariantTypeProperty.GetValues(Proc: TGetStrProc);
var
  i: Integer;
begin
  for i := 0 to High(VarTypeNames) do
    if VarTypeNames[i] <> '' then
      Proc(VarTypeNames[i]);
  Proc(SString);
end;

procedure TMyVariantTypeProperty.SetValue(const Value: string);

  function GetSelectedType: Integer;
  var
    i: Integer;
  begin
    Result := -1;
    for i := 0 to High(VarTypeNames) do
      if VarTypeNames[i] = Value then
      begin
        Result := i;
        break;
      end;
    if (Result = -1) and (Value = SString) then
      Result := varUString; // Исправляем для строковых значений
  end;

var
  NewType: Integer;
  V: Variant;
begin
  NewType := GetSelectedType;
  case NewType of
    varEmpty: VarClear(V);
    varNull: V := NULL;
    -1: raise EDesignPropertyError.CreateRes(@SUnknownType);
  else
    V := GetVarValue; // Перемещаем здесь для надежности
    try
      VarCast(V, V, NewType);
    except
      { Если не удалось привести к типу, очищаем и пытаемся снова }
      VarClear(V);
      VarCast(V, V, NewType);
    end;
  end;
  SetVarValue(V);
end;

{ TMyVariantProperty }

type
  TMyVariantProperty = class(TVariantProperty)
    procedure GetProperties(Proc: TGetPropProc); override;
  end;

procedure TMyVariantProperty.GetProperties(Proc: TGetPropProc);
begin
  Proc(TMyVariantTypeProperty.Create(Self));
end;

procedure Register;
begin
  // Изменяем 2-й и 3-й параметры, если хотите использовать этот редактор для всех свойств типа Variant
  RegisterPropertyEditor(TypeInfo(Variant), TTestComponent, 'CheckedValue', TMyVariantProperty);
end;

Вывод

Использование свойств типа Variant в Delphi может быть полезным, но требует внимательного подхода, особенно в режиме Design-Time. Стандартные редакторы свойств не всегда корректно работают с этим типом данных, поэтому рекомендуется вносить необходимые изменения в методы SetCheckedValue и IsCheckedValueStored, а также создавать кастомные редакторы свойств, если это необходимо. Эти решения помогут вам избежать ошибок и обеспечат корректную работу с типом Variant в вашем проекте.

Создано по материалам из источника по ссылке.

Статья описывает проблему некорректной работы стандартного инспектора свойств в Delphi с типом данных Variant и предлагает решения, включая исправление кода и создание кастомного редактора свойств.


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.


:: Главная :: Типы и Переменные ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-12-22 20:14:06
2025-06-16 01:39:26/0.0045218467712402/0