2012-03-31 16 views
1

我目前主要使用組件屬性的類型轉換頭痛。爲ini文件指定子組件屬性

在我的表格上,我有一個叫做「場景」的TPanel。同樣在窗體上,我有一個按鈕,創建一個TSelection,並在該TSelection創建一個TImage,然後將圖片加載到該TImage。 TSelection的名稱通過稱爲「ImgObjName」的TEdit分配。然後它將這個名字寫入一個inifile。 TS選擇的事件被分配給代碼中其他地方的過程。如您所知,TSelection組件可以在運行時移動(並調整大小)。 TImage將HitTest關閉,而TSelection已打開。

上面的工作,因爲我想要它,但下一部分是我卡住的地方。實質上,在計時器上,我想將每個子組件的一些選定屬性寫入TMemIniFile。有兩種方法我願意這樣做;
1)寫每個孩子的屬性來分開TMemInifiles。
2)將每個孩子的屬性寫入單個TMemIniFile,但使section確定該部分中的值與哪個組件相關。

我已經嘗試了幾種不同的方法,但它們都導致了我一些主要問題(通常是「索引越界」)。

我現在的方法是這樣的;

ChgPos是一個全局布爾變量,當TSelection對象之一上的mousedown事件觸發時爲TRUE,而MouseUp事件觸發時爲FALSE。這個布爾過程完全適用於這些目的,所以不需要改變。

TimerBar是在設計時創建的TTrackBar。它是基於計時器的值更改。

AnimIni是TMemIniFile,它已在代碼中早些分配。爲此,我已經設置它不釋放文件(因爲沒有訪問衝突)。

var 
    i: Integer; 
    PosX, PosY: Integer; 
begin 
    for i := 0 to Scene.ChildrenCount - 1 do 
    begin 
    if Scene.Components[i] is TSelection then 
    begin 
     PosX := AnimIni.ReadInteger(IntToStr(Round(TimerBar.Value)) + '_Object' + 
     IntToStr(i), 'PosX', PosX); 
     PosY := AnimIni.ReadInteger(IntToStr(Round(TimerBar.Value)) + '_Object' + 
     IntToStr(i), 'PosY', PosY); 
    end; 
    end; 
    if ChgPos = False then 
    begin 
    if Scene.Components[i] is TSelection then 
    begin 
     (Scene.Components[i] as TSelection).Position.X := PosX; 
     (Scene.Components[i] as TSelection).Position.Y := PosY; 
    end; 
    end 
    else if ChgPos = True then 
    begin 
    AnimIni.WriteInteger(IntToStr(Round(TimerBar.Value)) + '_Object' + 
     IntToStr(i), 'PosX', Round((Scene.Children[i] as TSelection).Position.X)); 
    AnimIni.WriteInteger(IntToStr(Round(TimerBar.Value)) + '_Object' + 
     IntToStr(i), 'PosY', Round((Scene.Children[i] as TSelection).Position.Y)); 
    end; 
end; 

我正在努力弄清楚該怎麼辦。我得到了「索引超出範圍」的錯誤。我還需要保存TImage組件的屬性(尤其是父級和位圖位置,但我覺得這對於至少使用一個組件的代碼至關重要)。

我對類型轉換有點新(因爲我之前的所有項目都不需要它),但是我迄今爲止的所有體驗都非常成功。只是在這種特殊情況下,事實證明,如果沒有一些幫助,我會變得更加複雜。

我曾嘗試WriteComponentReadComponent並使用多個文件流有關TimerBar的值實時數據,但它之多是爲了什麼我想要實現(特別是在寫入功能)太慢。 inifile方法從我以前的測試中起作用,但它實際上是在運行時創建的多個組件的類型轉換的工作,我遇到了問題。

任何人都可以闡明一個潛在的解決方案或我應該前往的方向?

+2

你的我的循環過快結束。我在你的'如果ChgPos'(和其他)的狀態是不確定的。 – 2012-03-31 06:33:15

回答

6
  1. 您正在混合組件和子項目。如果循環顯示面板的所有子項,請不要在Components屬性中使用該索引,而應該使用Children屬性。 (我假設你的代碼編譯和XE2有Children屬性,否則我認爲你的意思是ControlsControlCount)。
  2. 與LU RD已經評論過的一樣,您正在使用for循環外部的for循環變量i。我確定你想要它。您也可以通過編譯器警告此:

    for循環變量「我」可循環

    後未定義始終確保你有零!編譯器錯誤,警告和提示。

  3. 我不明白你的日常邏輯加載設置,即使你真的想寫它們。我想你只想在ChgPos爲false時從MemIniFile加載設置。

不能保證給定,但我認爲常規應該是這樣的(包括一些語法改進):

var 
    i: Integer; 
    Selection: TSelection; 
    PosX, PosY: Integer; 
begin 
    for i := 0 to Scene.ChildrenCount - 1 do 
    if Scene.Children[i] is TSelection then 
    begin 
     Selection := Scene.Children[i] as TSelection; 
     if ChgPos then 
     begin 
     AnimIni.WriteInteger(IntToStr(Round(TimerBar.Value)) + '_Object' + 
      IntToStr(i), 'PosX', Round(Selection.Position.X)); 
     AnimIni.WriteInteger(IntToStr(Round(TimerBar.Value)) + '_Object' + 
      IntToStr(i), 'PosY', Round(Selection.Position.Y)); 
     end 
     else 
     begin 
     PosX := AnimIni.ReadInteger(IntToStr(Round(TimerBar.Value)) + 
      '_Object' + IntToStr(i), 'PosX', PosX); 
     PosY := AnimIni.ReadInteger(IntToStr(Round(TimerBar.Value)) + 
      '_Object' + IntToStr(i), 'PosY', PosY); 
     Selection.Position.X := PosX; 
     Selection.Position.Y := PosY; 
     end; 
    end; 
end; 

雖然我嚴重懷疑爲AnimIni.ReadInteger功能的默認值,PosXPosY,這是未分配的。如果找不到ini文件中的部分,則PosXPosY將具有任意值。你應該將它們初始化爲任何有意義的東西。

+1

我想Children的財產必須是FMX。 – 2012-03-31 08:24:52

+0

這就是NGLN。 「兒童」確實是FMX的財產。 因爲它沒有關於循環的警告或暗示(並且只有關於我沒有從其他程序中使用的變量) 由於寫得很好的解釋和代碼糾正,我必須給這個投票你的回答,但是由於有幾個人有幫助,我已經把他們的每個答案都投了。 – 2012-03-31 13:40:39

3

您的循環計數器和索引屬性不匹配。 ComponentCountComponents[]走在一起。並且ChildrenCountChildren[]一起去。你想與後者配對,因爲你對控件的孩子很有趣。 ComponentCountComponents[]屬性是指所有權,這是一個不同的概念。

更重要的是你的循環結束了,但你繼續在循環變量後面使用循環變量。這顯然是錯誤的。它看起來像需要在循環內部和Scene.Children[i] is TSelection測試中。

由於旁邊ChildrenCount在語法上不正確,ComponentCountControlCount。這個屬性應該被命名爲ChildCount