2013-07-16 3 views
0

В моем приложении у меня есть много наборов определены:преобразование строки установить тип

eBlockTypes = (btNone,btUndefined,btStone, btYellowFlower, btWoodBrown...); 

sMinerals = set of eBlockTypes; 

var 
    mineralsRare: sMinerals; 
    mineralsPlants: sMinerals; 
    mineralsAll: sMinerals; 
    mineralsDeep: sMinerals; 
    mineralsWalkable: sMinerals; 
    mineralsDiggable: sMinerals; 

то у меня есть объект, который имеет «sMinerals», как один из его полей. Возможно ли прочитать «имя» набора при загрузке свойств объекта из файла?

Редактировать: подробнее. Допустим, что определение объекта в файл выглядит следующим образом:

[item] 
Computer 
[requires] 
3 Circuit board 
1 Medium CPU 
3 Plastic 
[placement] 
mineralsWalkable 

так что я могу разобрать файл и прочитать все свойства, кроме множества «mineralsWalkable». Я знаю, что я мог бы сравнить эту строку с некоторыми TStrings, содержащими все имена наборов, но quiestion: возможно ли это установить, преобразовывая строку в переменную как-то?

+0

Конечно, это возможное. Но вам нужно [изменить], чтобы дать более четкое объяснение того, что вы хотите сделать, прежде чем мы сможем рассказать вам, как это сделать. –

+0

Поиск [GetEnumValue] (http://docwiki.embarcadero.com/Libraries/XE4/en/System.TypInfo.GetEnumValue) и [GetEnumName] (http://docwiki.embarcadero.com/Libraries/XE4/en/System .TypInfo.GetEnumName). Это должно помочь в решении вашей проблемы ... наряду с довольно простым заявлением. – Sherlock70

+0

из того, что я прочитал, они могут преобразовать строку в элемент set, но не устанавливать 'type' – laggyluk

ответ

1

Что вы можете прочитать из файла, зависит от того, что находится в файле. Если вы введете имена ваших переменных в файл, вы также сможете их прочитать. Если нет, то вы не можете. Имена переменных не записываются в основном в файлы при написании данных.

Определите метод, используемый для записи имен в файл. Чтобы прочитать их, просто выполните обратную операцию. Если вы написали данные, разделенные каким-то образом, тогда прочитайте, пока не столкнетесь с разделителем. Если вам предшествовало имя с его длиной символа, то прочитайте длину, а затем прочитайте, что много символов. Если вы не пишете имена с помощью метода, который является обратимым, вам придется изменить способ написания данных, прежде чем приступать к его чтению.

Ваш вопрос спрашивает, можно ли читать имена, а ответ - да. С тех пор вы задали еще один вопрос: возможно ли «преобразовать» имя, считанное из файла, в фактическую переменную с соответствующим именем. Ответ на это - нет.

Обычные переменные не имеют RTTI; Delphi не поддерживает имена всех переменных в программе. Как только компилятор завершит свою работу, имена перестанут существовать в рамках программы.

Самый простой способ получить переменную - это настроить отображение из строки для установки значения. Прочитайте имя из файла, найдите имя в структуре данных и используйте соответствующее значение. A TDictionary<string, sMinerals> был бы идеален для этого. Просто заполните структуру данных, когда ваша программа запустится.

+0

Я написал ее «вручную»: объекты P предопределены и не требуют сохранения. Так что это имя переменной.Я знаю, что typeinfo может преобразовывать элементы набора в строку и обратно, но не знал, как это сделать с переменной типа «set», а не с элементами. – laggyluk

+0

Возможно, вы написали это вручную, но это было не мое. Вы написали его так, чтобы его можно было прочитать; в этом случае он сам по себе предшествует тому, что выглядит как фиксированный известный заголовок. Поэтому ищите заголовок, а затем читайте до следующей строки, и у вас есть строка. Я не понимаю, почему вы сомневались, что сможете прочитать это имя в первую очередь. –

+0

хорошо, я отредактировал вопрос, чтобы сделать его более понятным и взять «нет» для ответа – laggyluk

0

Pretty Simple ... Вам нужно сохранить переменные переменные, которые можно преобразовать в строковое представление ваших eBlockTypes. Вы будете использовать GetEnumName для этого. Затем вам нужно преобразовать строковое представление ваших eBlockTypes в фактический eBlockType, а затем добавить это к вашим минералам. Вы будете использовать GetEnumValue для этого.

Следующий пример показывает, принимая строковое представление ... поместив его в комплекте ..., а затем принимать множество ... и перемещая его обратно в строку ...

object Form54: TForm54 
    Left = 0 
    Top = 0 
    Caption = 'Form54' 
    ClientHeight = 290 
    ClientWidth = 554 
    Color = clBtnFace 
    Font.Charset = DEFAULT_CHARSET 
    Font.Color = clWindowText 
    Font.Height = -11 
    Font.Name = 'Tahoma' 
    Font.Style = [] 
    OldCreateOrder = False 
    OnCreate = FormCreate 
    OnDestroy = FormDestroy 
    PixelsPerInch = 96 
    TextHeight = 13 
    object Button1: TButton 
    Left = 56 
    Top = 160 
    Width = 75 
    Height = 25 
    Caption = 'Button1' 
    TabOrder = 0 
    OnClick = Button1Click 
    end 
    object Edit1: TEdit 
    Left = 56 
    Top = 64 
    Width = 265 
    Height = 21 
    TabOrder = 1 
    Text = 'Edit1' 
    end 
    object cbType1: TCheckBox 
    Left = 248 
    Top = 91 
    Width = 97 
    Height = 17 
    Caption = 'Type1' 
    TabOrder = 2 
    end 
    object cbType2: TCheckBox 
    Tag = 1 
    Left = 248 
    Top = 114 
    Width = 97 
    Height = 17 
    Caption = 'Type2' 
    TabOrder = 3 
    end 
    object cbType3: TCheckBox 
    Tag = 2 
    Left = 248 
    Top = 137 
    Width = 97 
    Height = 17 
    Caption = 'Type3' 
    TabOrder = 4 
    end 
end 

unit Unit54; 
{Note the code assumes cbType1.Tag = 0, cbType2.Tag = 1, and cbType3.Tag = 2} 
interface 

uses 
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
    Dialogs, StdCtrls, TypInfo, IniFiles; 

type 
    TMyType = (mtOne, mtTwo, mtThree); 
    TMyTypes= set of TMyType; 

    TForm54 = class(TForm) 
    Button1: TButton; 
    Edit1: TEdit; 
    cbType1: TCheckBox; 
    cbType2: TCheckBox; 
    cbType3: TCheckBox; 
    procedure Button1Click(Sender: TObject); 
    procedure FormCreate(Sender: TObject); 
    procedure FormDestroy(Sender: TObject); 
    private 
    function getTypes1: TMyTypes; 
    procedure setMyTypes1(const Value: TMyTypes); 
    { Private declarations } 

    public 
    { Public declarations } 
    property Types1: TMyTypes read getTypes1 write setMyTypes1; 

    procedure SaveMyTypes(aVariableName: string; aMyTypes: TMyTypes); 
    function ReadMyTypes(aVariableName: string): TMyTypes; 
    end; 

var 
    Form54: TForm54; 

implementation 

{$R *.dfm} 

procedure TForm54.Button1Click(Sender: TObject); 
var 
    a_MyTypes: TMyTypes; 
    a_Str: string; 
    a_Index: integer; 
begin 
    a_MyTypes := []; 
    a_Str := ''; 
    Include(a_MyTypes, TMyType(GetEnumValue(TypeInfo(TMyType), 'mtOne'))); 
    Include(a_MyTypes, TMyType(GetEnumValue(TypeInfo(TMyType), 'mtTwo'))); 
//purpoesly have mtThree3 instead of mtThree 
    Include(a_MyTypes, TMyType(GetEnumValue(TypeInfo(TMyType), 'mtThree3'))); 
    for a_Index := Ord(Low(TMyType)) to Ord(High(TMyType)) do 
    if TMyType(a_Index) in a_MyTypes then 
     if a_Str = '' then 
     a_Str := GetEnumName(TypeInfo(TMyType), a_Index) 
     else 
     a_Str := a_Str + ',' + GetEnumName(TypeInfo(TMyType), a_Index); 
//should be mtOne, mtTwo 
    Edit1.Text := a_Str; 
end; 

procedure TForm54.FormCreate(Sender: TObject); 
begin 
    Types1 := ReadMyTypes('Types1'); 
end; 

procedure TForm54.FormDestroy(Sender: TObject); 
begin 
    SaveMyTypes('Types1', Types1); 
end; 

function TForm54.getTypes1: TMyTypes; 
var 
    a_Index: integer; 
begin 
    Result := []; 
    for a_Index := 0 to Self.ComponentCount - 1 do 
    if Self.Components[a_Index] is TCheckBox and (TCheckBox(Self.Components[a_Index]).Checked) then 
     Include(Result, TMyType(Self.Components[a_Index].Tag)); 
end; 

function TForm54.ReadMyTypes(aVariableName: string): TMyTypes; 
var 
    a_Ini: TIniFile; 
    a_Var: string; 
    a_List: TStrings; 
    a_Index: integer; 
begin 
    Result := []; 
    a_Ini := nil; 
    a_List := nil; 
    a_Ini := TIniFile.Create('MyType.ini'); 
    a_List := TStringList.Create; 
    try 
    a_Var := a_Ini.ReadString('Sets', aVariableName, ''); 
    a_List.Delimiter := ','; 
    a_List.DelimitedText := a_Var; 
    for a_Index := 0 to a_List.Count - 1 do 
    begin 
     Include(Result, TMyType(GetEnumValue(TypeInfo(TMyType), a_List[a_Index]))); 
    end; 
    finally 
    a_Ini.Free; 
    a_List.Free; 
    end; 
end; 

procedure TForm54.SaveMyTypes(aVariableName: string; aMyTypes: TMyTypes); 
var 
    a_Ini: TIniFile; 
    a_Index: integer; 
    a_Var: string; 
begin 
    a_Var := ''; 
    a_Ini := TIniFile.Create('MyType.ini'); 
    try 
    for a_Index := Ord(Low(TMyType)) to Ord(High(TMyType)) do 
     if TMyType(a_Index) in aMyTypes then 
     if a_Var = '' then 
      a_Var := GetEnumName(TypeInfo(TMyType), a_Index) 
     else 
      a_Var := a_Var + ',' + GetEnumName(TypeInfo(TMyType), a_Index); 
    a_Ini.WriteString('Sets', aVariablename, a_Var); 
    finally 
    a_Ini.Free; 
    end; 
end; 

procedure TForm54.setMyTypes1(const Value: TMyTypes); 
var 
    a_Index: integer; 
begin 
    for a_Index := 0 to Self.ComponentCount - 1 do 
    if Self.Components[a_Index] is TCheckBox then 
     TCheckBox(Self.Components[a_Index]).Checked := TMyType(TCheckBox(Self.Components[a_Index]).Tag) in Value; 

end; 

end. 
+0

, все еще это преобразует элементы набора из строки и обратно. Я не хочу перечислять элементы в файле, так как их много, а наборы используются как метод группировки именно по этой причине. – laggyluk

+0

Я не понимаю, что вы хотите в своем файле, тогда ... Вы либо сохраняете значение переменной ... Переменная сама по себе ничего не значит ... Это означает что-то минералыDiggable = btStone, btYellowFlower. Таким образом, вы сохраняете это строковое представление в своем файле. –

+0

После просмотра типов ... выглядит как другой MineCraft;) –