0

It looks like I could use the RTTI to convert the enumerated type of a TFormBorderStyle property to String ans store it in my IniFile, and vise versa. However, I assumed I could typecast it back and forth from integer as well, but it does not seem to work. Why?

var
 Border: Integer = 3; 

procedure TfrmMain.FormCreate(Sender: TObject);
begin
 BorderStyle:= TFormBorderStyle(Border);
 pnlHeader.Visible:= ShowHeader;
 btnConfigure.Visible:= Configure;
 pnlFooter.Visible:= ShowFooter;
end;
IElite
  • 1,818
  • 9
  • 39
  • 64

2 Answers2

3

Although you are specifically asking for conversion to/from integer values, the conversion to/from string is not complicated (the prospect of "using RTTI" may be putting you off?) and I believe you may be better off using those given the requirement (storing values in an INI file).

You will be able to more clearly see what these values are then, even in the INI file, for example.

The code to convert to/from requires that you use the TypInfo unit, so given:

  uses TypInfo;

this code will yield the string representation of the form style:

  styleName := GetEnumName(TypeInfo(TFormBorderStyle), Ord(Form.BorderStyle));

and this code will yield the form style value of a string representing a form style enum:

  Form.BorderStyle := TFormBorderStyle(GetEnumValue(TypeInfo(TFormBorderStyle), styleName));

If you find yourself doing this more often in your code you could of course wrap them up inside some nice little helper functions, called (for example) BorderStyleToString(): String and BorderStyleFromString(): TFormBorderStyle

Deltics
  • 22,162
  • 2
  • 42
  • 70
  • Adding the overhead of RTTI unnecessarily to convert between a simple type and an integer seems pretty pointless to me. And, since the end user doesn't really care what the border style would look like in the INI file, making it human-readable at the expense of the overhead seems pretty wrong to me as well. It would be diffferent if there were other reasons to have access to RTTI, but for a simple integer/type conversion? – Ken White Mar 08 '11 at 03:10
  • And, thinking about it, this doesn't answer the question asked, which was how to do things *without* RTTI. Have to go -1 here. – Ken White Mar 08 '11 at 03:24
  • @Ken - remember that this is what is happening when a form is initialised from the dfm by TReader. There is no significant code overhead as far as linking additional units. – Gerry Coll Mar 08 '11 at 03:33
  • @Gerry, and that's why I didn't downvote on that portion, although adding RTTI to the unit does add some overhead where it wasn't before.. It was the failure to answer the original question (about doing it w/o RTTI) that garnered the -1. – Ken White Mar 08 '11 at 03:59
  • +1 But I think you need TypeInfo as first param to GetEnumName. `styleName := GetEnumName(TypeInfo(TFormBorderStyle), Ord(Form.BorderStyle));` – Mikael Eriksson Mar 08 '11 at 06:22
  • @Ken - see my blog post about answering the *need*, not necessarily the question as stated. I got the impression (rightly or wrongly) that the OP felt that using RTTI was complex, difficult or costly and that they were avoiding using it for these reasons rather than any practical or technical reasons. I also noted that the answer that DID answer the question immediately caused additional problems with how to correctly hardcast enums from integer literals. A complication that the RTTI based approach avoids and I therefore felt it worth illustrating how straightforward it actually was. – Deltics Mar 08 '11 at 20:09
  • @Ken - supplemental re overhead. The performance overhead is negligible to the point of being irrelevant, unless the OP's code is converting these values billions of times over in performance critical code. The typing overhead is noted, but if encapsulated in a pair of functions as suggested, that typing overhead is incurred once (in creating the wrapper functions), creating 100% safe conversion routines that are then even more easily used than hard casts of enums to/from integers. A stitch in time and all that... :) – Deltics Mar 08 '11 at 20:14
  • @Deltics - re your blog post: The usual way of doing things here (as no doubt you know) is to answer the question asked. If you then have a suggestion about another way of doing it, you make that suggestion as an addendum to the answer you've provided. Since the OP specifically asked about *without RTTI* and your answer was *RTTI*, it didn't answer the question asked. Re: Overhead - you're probably right, although there's still performance overhead involved in accessing RTTI in other locations after the dfm is streamed. Don't get me wrong = RTTI has it's purposes. Just not sure it's here. – Ken White Mar 10 '11 at 01:13
  • @Ken - yes he asks about the non-RTTI approach, but the wording of the question was very hazy about the reasons why. It is quite possible that he simply assumed that direct casting would be easier without having looked into what the RTTI approach involved. If the answer doesn't help, it won't get upvoted or accepted. But then again, if we only ever answered specifically the question explicitly answered, very often we end up answering the WRONG question (this SO question being a prime example: http://tinyurl.com/4ab8ons). – Deltics Mar 10 '11 at 20:30
2

Use Ord(bsDialog) to convert to an integer, and TBorderStyle(integervalue) to get back from integer.

IniFile.WriteInteger('YourForm', 'Border', Ord(YourForm.BorderStyle));
...
YourForm.BorderStyle := TFormBorderStyle(IniFile.ReadInteger('YourForm', 'Border', 0));
Ken White
  • 123,280
  • 14
  • 225
  • 444
  • Well, that's what he's already doing. You can see it in his code. His problem clearly lies elsewhere. – David Heffernan Mar 07 '11 at 23:48
  • OK, I still can't seem to get it to work. I need to store my main form's BorderStyle in an ini file. I dont care if I declare the variable "border" as an integer or as a TFormBorderStyle. However, i need to code to read and write the variable "border" to and from the ini file. Then the code to assign the variable to the Form's borderStyle property. With the default being bsSizeable (which i assume is 3 ??????) – IElite Mar 08 '11 at 00:03
  • @Shane: That is exactly what Ken's code is doing! But instead of `0` as the third argument of `ReadInteger`, you should use `ord(bsSizeable)` [which is `2`, not `3`]. [Btw, it would probably have been sufficient with one or two question marks.] – Andreas Rejbrand Mar 08 '11 at 00:09
  • Also, where Ken writes `TBorderStyle`, he should write `TFormBorderStyle`. – Andreas Rejbrand Mar 08 '11 at 00:13
  • Sorry, but the code does not work. I am using Delphi 2010 (Rad Studio) and using his code does not change the BorderStyle of my form. I get no errors, it just always stays the default bsSizeable. I tried different integers from 0 - 5 and nothing changed it. Oh well, no biggie.....i can move on to something else and come back and play with this at another date. Dont want to waste to much time on it – IElite Mar 08 '11 at 00:18
  • @Shane: Post your actual code that you claim isn't working. My code works fine in Delphi XE, so it's something else you're doing wrong. @Andreas Rejbrand: Thanks for the catch on the typecast name. – Ken White Mar 08 '11 at 00:20
  • Ken, it was the values. I assumed it was (bsDialog, bsNone, bsSingle, bsSizeable, etc) ....0,1,2,3 or possibley 1,2,3,4. I guess i was wrong, it bsSizeable = 2. – IElite Mar 08 '11 at 00:27
  • In forms.pas - the enumerated types are (bsNone, bsSingle, bsSizeable....) - however, in Delphi's Object Inspector they seem to be sorted alphabetically and it was throwing the values off. Anyway, its fixed now, Thanks for the help. – IElite Mar 08 '11 at 00:30
  • 1
    @Shane: At any rate, you should *never* write the actual numbers `0`, `1`, `2`, etc. Instead, you should use `ord(bsNone)`, `ord(bsSingle)`, `ord(bsSizeable)` etc. – Andreas Rejbrand Mar 08 '11 at 00:34
  • Pretty pointless saying you should never write integer literals rather than enum names when the net result of the exercise is to circumvent the protection/peace of mind that using the enum names gives you. Given the requirements - storing a value in an INI file, I'd say the poster would be better off being given a couple of one liner routines to do the string conversions. – Deltics Mar 08 '11 at 02:57
  • this has out of range enum writ large – David Heffernan Mar 08 '11 at 05:27
  • @Deltics: Well, the mistake the OP did was in fact to assume that `bsSizeable` was `3` (and not `2`). Had he written `ord(bsSizeable)` this question would't even have been asked. – Andreas Rejbrand Mar 08 '11 at 11:52
  • @Andreas - I'm not so sure of that. The first comment to his question states that `3` is `bsDialog`, and in one of his comments, OP states that he *"tried different integers from 0 - 5 and nothing changed"*. – Sertac Akyuz Mar 08 '11 at 15:44
  • 1
    @Sertac: I don't know, but I read Shane above: "Ken, it was the values. I assumed it was (bsDialog, bsNone, bsSingle, bsSizeable, etc) ....0,1,2,3 or possibley 1,2,3,4. I guess i was wrong, it bsSizeable = 2" – Andreas Rejbrand Mar 08 '11 at 15:46