Helper for Enum Type (Delphi XE)

I’ve never created class / record helpers before but have read about them.

Is it possible in XE to create a helper for an enumerated type to return a string?

type
  TOrientation = (
    oHorizontal,
    oVertical,
    oDiagonal
    );

So if I have a variable of TOrientation (say O), I like to be able to do:

xxx.Caption := O.ToString;

I’ve tried this in XE but get an error “Record type required”.

For now I’m just creating an array of the type with the text versions of each value.

I believe this was added in XE3

  TOrientationHelper= record helper for TOrientation 
    function ToString: string;
  end;

Perhaps it’s time to move on from XE :wink:

hi David,

I’ve been converting enumerated types to strings and back using the following fossilized remains from Delphi 2007. You might be able to use something similar.

type

TToolType = (tNone,tDrill,tRecipKnife,tPen,tCreaseTool,tHeadCam,tPunch,tLaserPointer);

//Uses TypInfo.pas

function ToolTypeToStr(t:TToolType):String;
{
Return the tSomething as as string.
}
begin
try
result := GetEnumName(TypeInfo(TToolType), ord(t));
except
On E:Exception do
result := ‘UnknownTool’+IntToStr(ord(t));
end;
end;

function StrToToolType(s:string):TToolType;
{
Return the tool type implied by s.
}
var
k :integer;
begin
//Get the ordinal value of the corresponding tool type.
k := GetEnumValue(Typeinfo(TToolType), s);
if k<0 then
result := tNone //unknown tool type.
else
result := TToolType(k);
end;

Hi David

You can always create a constant

const
OrientationNames = array[TOrientation] of string = (‘Horizontal’, ‘Vertical’, ‘Diagonal’);

A technique I use to achieve what I think you are trying to do is this;

Type

TOrientation = (oHorizontal, oVertical, oDiagonal);

Const c_OrientationDesc: array[TOrientation] of string = (‘Horizontal’, ‘Vertical’, ‘Diagonal’);

xxx.Caption := c_OrientationDesc[O];

A constant array or function is what I’ve been using for some time now.

It looks like I can’t really do any better than that.

What I do now works, but when I see something that looks neater I like to try it.

If I port this project from XE to the community edition one day I can revisit it.

Thanks gents.

Have you seen the code formatting FAQ? For example

type

TToolType = (tNone,tDrill,tRecipKnife,tPen,tCreaseTool,tHeadCam,tPunch,tLaserPointer);

//Uses TypInfo.pas

function ToolTypeToStr(t:TToolType):String;
{
Return the tSomething as as string.
}
begin
try
result := GetEnumName(TypeInfo(TToolType), ord(t));
except
On E:Exception do
result := ‘UnknownTool’+IntToStr(ord(t));
end;
end;

Also David, if you think there is nothing more to be gained from this topic, you might like to try marking it as solved. Learn something new every day and earn yourself a badge. :wink:

Was that a formatting FAQ here somewhere ?

I got sick of writing enum specific code for converting them to a string, so using generics, I’ve created my own method for converting any Enum type to a human readable form with a simple call to: TDataUtils.EnumValueToString(Value)

Keep in mind that some of this code is quite old and could be improved with a bit of refactoring.

This should give a result of ‘Create Tool’ when called with TDataUtils.EnumValueToString(tCreaseTool)

type
  TDataUtils = class
    class function EnumValueToString<T>(Value: T): string;
  end;

implementation

function FirstCapitalPos(s: string): Integer;
var
  i: Integer;
begin
  Result := 0;

  for i := 0 to Length(s) - 1 do
    begin
      if CharInSet(s[i + Low(s)], ['A'..'Z']) then
        exit(i + 1);
    end;
end;

function RemoveEnumPrefix(s: string): string;
var
  Index: Integer;
begin
  Index := Pos(s, '_');

  if Index <= 0 then
    Index := FirstCapitalPos(s) - 1;

  if Index < 0 then
    Index := 0;

  Result := Copy(s, Index + 1, Length(s) - Index);
end;

function LowCase(ch: char): char;
begin
  Result := ch;
  case Result of
    'A' .. 'Z':
      Inc(Result, Ord('a') - Ord('A'));
  end;
end;

function IsCapital(ch: Char): Boolean;
begin
  Result := LowCase(ch) <> ch;
end;

function InsertSpacesBeforeCapitals(const s: string): string;
var
  i: Integer;
  ch: Char;
  InsertSpace: Boolean;
  LowerBefore: Boolean;
  LowerAfter: Boolean;
begin
  Result := Copy(s, 1, 1);

  for i := Low(s) + 1 to High(s) do
    begin
      ch := s[i];

      if IsCapital(ch) then
        begin
          if i < High(s) then
            LowerAfter := not IsCapital(s[i + 1])
          else
            LowerAfter := False;

          if LowerAfter then
            InsertSpace := True
          else
            begin
              LowerBefore := not IsCapital(s[i - 1]);

              InsertSpace := LowerBefore;
            end;

          if InsertSpace then
            Result := Result + ' ';
        end;

      Result := Result + ch;
    end;
end;

class function TDataUtils.EnumValueToString<T>(Value: T): string;
var
  ValueString: string;
begin
  ValueString := TValue.From(Value).ToString;
  Result      := InsertSpacesBeforeCapitals(RemoveEnumPrefix(ValueString));
end;

As an aside, if you’re not wanting to make the string nicely formatted for humans, you can just call:

1 Like

Yes, under Site Feedback subcategory FAQ. There are a number of other FAQs there as well.

being picky …

TValue.From<T>(Value).ToString

Nope - no need to pass the type in - the compiler can figure that out automatically.

1 Like

Hi,

Just testing the code formatting as Sue suggested:


function test(j:integer):integer

begin

result := j*(j+1);

end;