Solved

Can't move TShape while app is runing after....

Posted on 2010-11-19
28
648 Views
Last Modified: 2012-05-10
To the attached code  i have added :

TShapeFSelectedShapelabel.Left:= _Pos.X + Mouse.CursorPos.X;
 FSelectedShapelabel.Top := _Pos.Y + Mouse.CursorPos.Y - 12;

to move TLabel behind the Tshape. until here everything it's alright. But after restarting of app and reading from ini file. I can't move tshapes any more because app goes to error:
Project Forma.exe raised exception class EAccessViolation with message 'Access violation at address 0044C54C in module 'Forma.exe'. Read of address 00000048'.


procedure TForm1.ShapeMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  // i now make a difference between selecting and dragging a shape
  // this make it possible to keep a selection and that is usefull for the speedbutton function
  FSelectedShape := TShape(Sender); // Might be usefull for other treatments
  if Assigned(FSelectedShape) then begin
      //ShapeMenu: TPopupMenu;
   if ssRight in Shift Then  PopupMenu1.Popup(Mouse.CursorPos.X,Mouse.CursorPos.Y);
   if ssLeft in Shift then begin
    // set the last clicked shape with right button
    // get its start position relative to position of mouse when the click occurred
    _Pos.X := FSelectedShape.Left-Mouse.CursorPos.X;
    _Pos.Y := FSelectedShape.Top-Mouse.CursorPos.Y;
    FDragShape := FSelectedShape;
    end;
  end;
end;

procedure TForm1.ShapeMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
  // only dragging with left mouse button
  if Not (ssLeft in Shift) then FDragShape := nil;
  if Not Assigned(FDragShape) then Exit;
  // Don't use X & Y directly as they are relative to the object, which is moving
  FDragShape.Left := _Pos.X + Mouse.CursorPos.X;
  FDragShape.Top := _Pos.Y + Mouse.CursorPos.Y;
 FSelectedShapelabel.Left:= _Pos.X + Mouse.CursorPos.X;
 FSelectedShapelabel.Top := _Pos.Y + Mouse.CursorPos.Y - 12;
end;

procedure TForm1.ShapeMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  //finish the drag
  FDragShape := nil;
end;

Open in new window

0
Comment
Question by:pr2501
  • 9
  • 8
  • 6
  • +1
28 Comments
 
LVL 24

Expert Comment

by:jimyX
ID: 34173211
What about the initialization most probably it is a problem of assigning invalid values to the components/variables or setting mismatched datatypes when reading from the ini file.

Also:
1>  To the attached code  i have added
2>  TShapeFSelectedShapelabel.Left:= _Pos.X + Mouse.CursorPos.X;
3>  FSelectedShapelabel.Top := _Pos.Y + Mouse.CursorPos.Y - 12;

Why the line 2 is "TShapeFSelectedShapelabel" and line 3 is "FSelectedShapelabel" shouldn't they be the same object ?
0
 
LVL 32

Expert Comment

by:ewangoya
ID: 34173727

Make changes here as well

procedure TForm1.ShapeMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  // i now make a difference between selecting and dragging a shape
  // this make it possible to keep a selection and that is usefull for the speedbutton function
  if Assigned(Sender) and (Sender is TShape) then
  begin
   FSelectedShape := TShape(Sender); // Might be usefull for other treatments
      //ShapeMenu: TPopupMenu;
   if ssRight in Shift Then  
   begin
       PopupMenu1.Popup(Mouse.CursorPos.X,Mouse.CursorPos.Y);
       Exit;
   end;
   if ssLeft in Shift then begin
    // set the last clicked shape with right button
    // get its start position relative to position of mouse when the click occurred
    _Pos.X := FSelectedShape.Left-Mouse.CursorPos.X;
    _Pos.Y := FSelectedShape.Top-Mouse.CursorPos.Y;
    FDragShape := FSelectedShape;
    end;
  end;
end;
0
 
LVL 25

Expert Comment

by:epasquier
ID: 34184757
All the changes proposed are good advices, but they probably won't solve the real problem, which is probably that you don't initialize the objects the same way when you create them dynamically from GUI or from Ini file.
Ewangoya probably touch the cause by checking if the sender of these events is of TShape type
But since it SHOULD BE, I recommend not only checking but raising an exception.
You will say : why raise an exception to avoid another exception instead of simply masking the problem doing nothing ? because you would know for sure that you incorrectly initialize the events of your dynamically created objets, and if you stop execution when that occurs you can see in Debug evaluation/watch the Sender.ClassName and Sender.Name to know exactly which component is the problem


procedure TForm1.ShapeMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
 FSelectedShape := Sender As TShape; // Raise an exception if not the case
 if Shift=[ssRight] Then PopupMenu1.Popup(Mouse.CursorPos.X,Mouse.CursorPos.Y);
 if Shift=[ssLeft] then
  begin
   _Pos.X := FSelectedShape.Left-Mouse.CursorPos.X;
   _Pos.Y := FSelectedShape.Top-Mouse.CursorPos.Y;
   FDragShape := FSelectedShape;
  end;
end;

Open in new window

0
Networking for the Cloud Era

Join Microsoft and Riverbed for a discussion and demonstration of enhancements to SteelConnect:
-One-click orchestration and cloud connectivity in Azure environments
-Tight integration of SD-WAN and WAN optimization capabilities
-Scalability and resiliency equal to a data center

 

Author Comment

by:pr2501
ID: 34185955
I have attached reading from ini to help clear the situation:
procedure TForm1.FormCreate(Sender: TObject);

var
  cmp: TShape;
  Lbel : TLabel;
  i: integer;
  Fname:string;

begin

    LabelNumber := 0;

   with TINIFile.Create(ExtractFilePath(Application.Exename) + 'yourinilabel.ini')do  begin //2
    try
     caption:= ReadString(Self.Name, 'Caption', Caption);
       LoadBackground( ReadString('_global_', 'bitmapfile', '' ) );
       pathstrBitmapFile:=  ReadString('_global_', 'bitmapfile', '' );

    n:=0;
       n := ReadInteger(Self.Name, 'Label', 0);
       edit2.Text:=inttostr(n);
         i:=1;
       for i := 1 to n do
       begin
         Lbel := TLabel(form1.FindComponent('Label' + IntToStr(i)));
         if Lbel = nil then begin
             Lbel := TLabel.Create(Self);
             Lbel.Name := 'Label' + IntToStr(I);
             Lbel.Parent := Self;
             //Lbel.onClick := LabelClick;
             inc(LabelNumber);
             Lbel.Caption := ReadString(Self.Name, Lbel.Name + ' Caption', TLabel(Lbel).Caption);
             Lbel.Font.Color := TColor(ReadInteger(Self.Name, Lbel.Name + ' Font Color', integer(clWindowText)));
             Lbel.Font.name := ReadString(Self.Name, Lbel.Name + ' Font Name', TLabel(Lbel).Font.Name);
             Lbel.Font.Size := ReadInteger(Self.Name, Lbel.Name + ' Font Size', TLabel(Lbel).Font.Size);
             Lbel.Top := ReadInteger(Self.Name, Lbel.Name + ' Top', Lbel.Top);
             Lbel.Left := ReadInteger(Self.Name, Lbel.Name + ' Left', Lbel.Left);
            // Lbel.AutSize := ReadBool(Self.Name, Lbel.Name + ' AutoSize', TLabel(Lbel).AutoSize);
             Lbel.Transparent := ReadBool(Self.Name, Lbel.Name + ' Transparent', TLabel(Lbel).Transparent);
             Lbel.WordWrap := ReadBool(Self.Name, Lbel.Name + ' WordWrap', TLabel(Lbel).WordWrap);
         end;
       end;
    finally
    free;
    end;



     FShapeNumber := 0;
    with TINIFile.Create(ExtractFilePath(Application.Exename) + 'yourinishape.ini')do  begin //2
      try

        n := ReadInteger(Self.Name, 'Shapes', 0);
        edit1.Text:=inttostr(n);
          i:=1;
       for i := 1 to n do begin
       // if you use TShape as class, you only need to cast once
         cmp := TShape(FindComponent('Shape' + IntToStr(i)));
         if cmp = nil then  begin
          cmp := TShape.Create(Self);
          cmp.Name := 'Shape' + IntToStr(I);
          cmp.Parent := Self;
          cmp.onMouseDown := ShapeMouseDown;
          cmp.onMouseMove := ShapeMouseMove;
          cmp.onMouseUp := ShapeMouseUp;
          cmp.Tag := FShapeNumber;
          inc(FShapeNumber);
          cmp.Brush.Color := TColor(ReadInteger(Self.Name, cmp.Name + ' Brush Color', integer(clGreen)));
          cmp.Width := ReadInteger(Self.Name, cmp.Name + ' Width', cmp.Width);
          cmp.Height := ReadInteger(Self.Name, cmp.Name + ' Height', cmp.Height);
          cmp.Top := ReadInteger(Self.Name, cmp.Name + ' Top', cmp.Top);
          cmp.Left := ReadInteger(Self.Name, cmp.Name + ' Left', cmp.Left);
          cmp.hint :=readString(Self.Name, cmp.Name + ' Hint',TShape(cmp).Hint);
          cmp.showhint :=readBool(Self.Name, cmp.Name + ' ShowHint',TShape(cmp).Showhint);
         end;
       end;
      finally
      free;
      end;
     Application.Showhint := true;
  end;

  end;
end;

Open in new window

0
 
LVL 24

Expert Comment

by:jimyX
ID: 34185973
Can you also attach the code of saving the Shape to the ini ?
0
 

Author Comment

by:pr2501
ID: 34186012
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
      begin
    storeinilabel();
   storeinishape();

        end ;

  //aaaaaaaaaaaaaaaaaaaaaaaa
  procedure tform1.storeinilabel();
var
  cmplabel: tcomponent;
  j: integer;
  Fname:string;
  E: TIniFile;
begin
  E := TINIFile.Create(ExtractFilePath(Application.Exename) + 'yourinilabel.ini');
  try
        e.EraseSection(Self.Name);
     e. WriteString(Self.Name, 'Caption', Caption);
      e.WriteString('_global_', 'bitmapfile', pathstrBitmapFile) ;
     
     j := 1;
    cmpLabel := FindComponent('Label' + IntToStr(j));

    while cmpLabel <> nil do
    begin
       E.WriteInteger(Self.Name, cmpLabel.Name + ' Top', integer(TLabel(cmpLabel).Top));
       E.WriteInteger(Self.Name, cmpLabel.Name + ' Left', integer(TLabel(cmpLabel).Left));
      //F.WriteString(Self.Name, cmp.Name + ' Hint',TShape(cmp).Hint);
       E.WriteString(Self.Name, cmpLabel.Name + ' Caption', TLabel(cmpLabel).Caption);

         j := j + 1;
       cmpLabel := FindComponent('Label' + IntToStr(j));
       if cmplabel = nil then
         E.WriteInteger(Self.Name, 'Label', j-1);
       end;
  //     edit1.Text:= cmpLabel.Name;
       //
  finally
   E.free;
  end ;
end;

  procedure tform1.storeinishape();
  var
  cmp: tcomponent;
  i: integer;
  Fname:string;
  F: TIniFile;
  begin
   F:=TINIFile.Create(ExtractFilePath(Application.Exename) + 'yourinishape.ini');
   try
      F.WriteString('APPLICATION','NAME',ExtractFileName(Application.ExeName));
       F.WriteString('APPLICATION','PATH',ExtractFilePath(Application.ExeName));
      F.WriteString('APPLICATION','INI', ExtractFilePath(Application.ExeName) + 'app.ini');
     i := 1;
      cmp := FindComponent('Shape' + IntToStr(i));
     while cmp <> nil do
     begin
       F.WriteInteger(Self.Name, cmp.Name + ' Brush Color', integer(TShape(cmp).Brush.Color));
       // WriteInteger('Form1', cmp.Name + ' Width', TShape(cmp).Width); --> less complex
       F.WriteInteger(Self.Name, cmp.Name + ' Width', integer(TShape(cmp).Width));
       F.WriteInteger(Self.Name, cmp.Name + ' Height', integer(TShape(cmp).Height));
       F.WriteInteger(Self.Name, cmp.Name + ' Top', integer(TShape(cmp).Top));
       F.WriteInteger(Self.Name, cmp.Name + ' Left', integer(TShape(cmp).Left));
       F.WriteString(Self.Name, cmp.Name + ' Hint',TShape(cmp).Hint);
       F.WriteBool(Self.Name, cmp.Name + ' ShowHint',TShape(cmp).Showhint);

       i := i + 1;
       cmp := FindComponent('Shape' + IntToStr(i));
       if cmp = nil then  F.WriteInteger(Self.Name, 'Shapes', i-1);
      end;
    finally
  F.free;
    end;

  end;

Open in new window

0
 
LVL 25

Expert Comment

by:epasquier
ID: 34186145
can you do the modifications we talked about and tell us exactly on which line it raise an exception ?
0
 

Author Comment

by:pr2501
ID: 34187392
First chance exception at $7C812AFB. Exception class EAccessViolation with message 'Access violation at address 0044C54C in module 'Forma.exe'. Read of address 00000048'. Process Forma.exe (2860)

And if a click on brake it does'n check me the line in code.
0
 
LVL 25

Expert Comment

by:epasquier
ID: 34187438
when does this occur ? when you click on a shape ? when you start draging it ?
can't you put a breakpoint on those events and execute line by line ?
0
 
LVL 24

Expert Comment

by:jimyX
ID: 34188257
A minor changes which might fix that, please try this, replace your FormCreate with this one:

procedure TForm1.FormCreate(Sender: TObject);
var
  cmp: TShape;
  Lbel : TLabel;
  i: integer;
  Fname:string;
  iniLbel, inishape : Tinifile;
begin
  LabelNumber := 0;

  inilbel := TINIFile.Create(ExtractFilePath(Application.Exename) + 'yourinilabel.ini')
  try
    caption:= inilbel.ReadString(Self.Name, 'Caption', Caption);
    LoadBackground( inilbel.ReadString('_global_', 'bitmapfile', '' ) );
    pathstrBitmapFile:=  inilbel.ReadString('_global_', 'bitmapfile', '' );

    n:=0;
    n := inilbel.ReadInteger(Self.Name, 'Label', 0);
    edit2.Text:=inttostr(n);
    i:=1;
    for i := 1 to n do
      begin
        Lbel := TLabel(form1.FindComponent('Label' + IntToStr(i)));
        if Lbel = nil then
          begin
            Lbel := TLabel.Create(Self);
            Lbel.Name := 'Label' + IntToStr(I);
            Lbel.Parent := Self;
            //Lbel.onClick := LabelClick;
            inc(LabelNumber);
            Lbel.Caption := inilbel.ReadString(Self.Name, Lbel.Name + ' Caption', TLabel(Lbel).Caption);
            Lbel.Font.Color := TColor(inilbel.ReadInteger(Self.Name, Lbel.Name + ' Font Color', integer(clWindowText)));
            Lbel.Font.name := inilbel.ReadString(Self.Name, Lbel.Name + ' Font Name', TLabel(Lbel).Font.Name);
            Lbel.Font.Size := inilbel.ReadInteger(Self.Name, Lbel.Name + ' Font Size', TLabel(Lbel).Font.Size);
            Lbel.Top := inilbel.ReadInteger(Self.Name, Lbel.Name + ' Top', Lbel.Top);
            Lbel.Left := inilbel.ReadInteger(Self.Name, Lbel.Name + ' Left', Lbel.Left);
            // Lbel.AutSize := inilbel.ReadBool(Self.Name, Lbel.Name + ' AutoSize', TLabel(Lbel).AutoSize);
            Lbel.Transparent := inilbel.ReadBool(Self.Name, Lbel.Name + ' Transparent', TLabel(Lbel).Transparent);
            Lbel.WordWrap := inilbel.ReadBool(Self.Name, Lbel.Name + ' WordWrap', TLabel(Lbel).WordWrap);
          end;   // if nil
       end;  // for-loop
  finally
    inilbel.free;
  end;  // try label

  FShapeNumber := 0;
  inishape := TINIFile.Create(ExtractFilePath(Application.Exename) + 'yourinishape.ini');
  try
    n := inishape.ReadInteger(Self.Name, 'Shapes', 0);
    edit1.Text:=inttostr(n);
    i:=1;
    for i := 1 to n do
      begin
        // if you use TShape as class, you only need to cast once
        cmp := TShape(FindComponent('Shape' + IntToStr(i)));
        if cmp = nil then 
          begin
            cmp := TShape.Create(Self);
            cmp.Name := 'Shape' + IntToStr(I);
            cmp.Parent := Self;
            cmp.onMouseDown := ShapeMouseDown;
            cmp.onMouseMove := ShapeMouseMove;
            cmp.onMouseUp := ShapeMouseUp;
            cmp.Tag := FShapeNumber;
            inc(FShapeNumber);
            cmp.Brush.Color := TColor(inishape.ReadInteger(Self.Name, cmp.Name + ' Brush Color', integer(clGreen)));
            cmp.Width := inishape.ReadInteger(Self.Name, cmp.Name + ' Width', cmp.Width);
            cmp.Height := inishape.ReadInteger(Self.Name, cmp.Name + ' Height', cmp.Height);
            cmp.Top := inishape.ReadInteger(Self.Name, cmp.Name + ' Top', cmp.Top);
            cmp.Left := inishape.ReadInteger(Self.Name, cmp.Name + ' Left', cmp.Left);
            cmp.hint := inishape.readString(Self.Name, cmp.Name + ' Hint',TShape(cmp).Hint);
            cmp.showhint := inishape.readBool(Self.Name, cmp.Name + ' ShowHint',TShape(cmp).Showhint);
          end;   if nil
        end;  // for-loop
  finally
    inishape.free;
  end;  // try shape

  Application.Showhint := true;
end;

Open in new window

0
 
LVL 25

Expert Comment

by:epasquier
ID: 34188395
what have you changed exactly ?
0
 
LVL 32

Expert Comment

by:ewangoya
ID: 34188728

>what have you changed exactly ?

I have no idea as well

clean up the read shape to this firstFShapeNumber := 0;
  inishape := TINIFile.Create(ExtractFilePath(Application.Exename) + 'yourinishape.ini');
  try
    n := inishape.ReadInteger(Self.Name, 'Shapes', 0);
    edit1.Text:=inttostr(n);
    //i:=1; What is this ???
    for i := 1 to n do
    begin
      // if you use TShape as class, you only need to cast once
      cmp := TShape(FindComponent('Shape' + IntToStr(i)));
      if cmp = nil then
      begin
        cmp := TShape.Create(Self);
        cmp.SetSubComponent(True);
        cmp.Name := 'Shape' + IntToStr(I);
        cmp.Parent := Self;

        cmp.Tag := FShapeNumber;
        inc(FShapeNumber);
        cmp.Brush.Color := TColor(inishape.ReadInteger(Self.Name, cmp.Name + ' Brush Color', integer(clGreen)));
        cmp.Width := inishape.ReadInteger(Self.Name, cmp.Name + ' Width', cmp.Width);
        cmp.Height := inishape.ReadInteger(Self.Name, cmp.Name + ' Height', cmp.Height);
        cmp.Top := inishape.ReadInteger(Self.Name, cmp.Name + ' Top', cmp.Top);
        cmp.Left := inishape.ReadInteger(Self.Name, cmp.Name + ' Left', cmp.Left);
        cmp.hint := inishape.readString(Self.Name, cmp.Name + ' Hint', ''); //There is no hint yet TShape(cmp).Hint
        cmp.showhint := inishape.readBool(Self.Name, cmp.Name + ' ShowHint', cmp.Hint <> '');  //Show Hint is false, TShape(cmp).Showhint

        cmp.onMouseDown := ShapeMouseDown;
        cmp.onMouseMove := ShapeMouseMove;
        cmp.onMouseUp := ShapeMouseUp;
      end;
    end;  // for-loop
  finally
    FreeAndNil(inishape);
  end;  // try shape



0
 
LVL 24

Assisted Solution

by:jimyX
jimyX earned 150 total points
ID: 34188742
1. Added iniLbel, inishape : Tinifile; so when calling "free" in the Try-Finally it won't mix up with other objects.

2. At a certain point the two With-Do's were overlapping and both of them were terminated at the end of the procedure:

   with TINIFile.Create(ExtractFilePath(Application.Exename) + 'yourinilabel.ini')do  begin //2

with TINIFile.Create(ExtractFilePath(Application.Exename) + 'yourinishape.ini')do  begin //2

3. Code ordering.

Till this point that's the only comment that was left not pointed out by experts about the provided code and If there is anything wrong it is lessen to be from somewhere else but not what we have been discussing so far.

0
 
LVL 25

Expert Comment

by:epasquier
ID: 34188863
You are probably right Jimy, and for the moment I still don't know WHEN the problem occurs... We're walking blind in the dark here
0
 
LVL 32

Expert Comment

by:ewangoya
ID: 34189004
No need for multiple ini files

procedure TForm1.FormCreate(Sender: TObject);
var
  cmp: TShape;
  Lbel : TLabel;
  i: integer;
  IniFile: TiniFile;
begin
  LabelNumber := 0;

  IniFile := TINIFile.Create(ExtractFilePath(Application.Exename) + 'yourinilabel.ini')
  try
    caption:= inilbel.ReadString(Self.Name, 'Caption', Caption);
    LoadBackground( inilbel.ReadString('_global_', 'bitmapfile', '' ) );
    pathstrBitmapFile:=  inilbel.ReadString('_global_', 'bitmapfile', '' );

    n:=0;
    n := inilbel.ReadInteger(Self.Name, 'Label', 0);
    edit2.Text:=inttostr(n);
    //i:=1; remove
    for i := 1 to n do
    begin
      Lbel := TLabel(form1.FindComponent('Label' + IntToStr(i)));
      if Lbel = nil then
      begin
        Lbel := TLabel.Create(Self);
        Lbel.Name := 'Label' + IntToStr(I);
        Lbel.Parent := Self;
        //Lbel.onClick := LabelClick;
        inc(LabelNumber);
        Lbel.Caption := inilbel.ReadString(Self.Name, Lbel.Name + ' Caption', TLabel(Lbel).Caption);
        Lbel.Font.Color := TColor(inilbel.ReadInteger(Self.Name, Lbel.Name + ' Font Color', integer(clWindowText)));
        Lbel.Font.name := inilbel.ReadString(Self.Name, Lbel.Name + ' Font Name', TLabel(Lbel).Font.Name);
        Lbel.Font.Size := inilbel.ReadInteger(Self.Name, Lbel.Name + ' Font Size', TLabel(Lbel).Font.Size);
        Lbel.Top := inilbel.ReadInteger(Self.Name, Lbel.Name + ' Top', Lbel.Top);
        Lbel.Left := inilbel.ReadInteger(Self.Name, Lbel.Name + ' Left', Lbel.Left);
        // Lbel.AutSize := inilbel.ReadBool(Self.Name, Lbel.Name + ' AutoSize', TLabel(Lbel).AutoSize);
        Lbel.Transparent := inilbel.ReadBool(Self.Name, Lbel.Name + ' Transparent', TLabel(Lbel).Transparent);
        Lbel.WordWrap := inilbel.ReadBool(Self.Name, Lbel.Name + ' WordWrap', TLabel(Lbel).WordWrap);
      end;   // if nil
    end;

    FShapeNumber := 0;
    n := inishape.ReadInteger(Self.Name, 'Shapes', 0);
    edit1.Text:=inttostr(n);
    //i:=1; remove
    for i := 1 to n do
    begin
      // if you use TShape as class, you only need to cast once
      cmp := TShape(FindComponent('Shape' + IntToStr(i)));
      if cmp = nil then
      begin
        cmp := TShape.Create(Self);
        cmp.Name := 'Shape' + IntToStr(I);
        cmp.Parent := Self;
        cmp.Tag := FShapeNumber;
        inc(FShapeNumber);
        cmp.Brush.Color := TColor(inishape.ReadInteger(Self.Name, cmp.Name + ' Brush Color', integer(clGreen)));
        cmp.Width := inishape.ReadInteger(Self.Name, cmp.Name + ' Width', cmp.Width);
        cmp.Height := inishape.ReadInteger(Self.Name, cmp.Name + ' Height', cmp.Height);
        cmp.Top := inishape.ReadInteger(Self.Name, cmp.Name + ' Top', cmp.Top);
        cmp.Left := inishape.ReadInteger(Self.Name, cmp.Name + ' Left', cmp.Left);
        cmp.hint := inishape.readString(Self.Name, cmp.Name + ' Hint', '');
        cmp.showhint := inishape.readBool(Self.Name, cmp.Name + ' ShowHint', cmp.hint<>'');

        cmp.onMouseDown := ShapeMouseDown;
        cmp.onMouseMove := ShapeMouseMove;
        cmp.onMouseUp := ShapeMouseUp;
      end;
    end;  // for-loop
  finally
    FreeAndNil(IniFile);
  end;  // try shape

  Application.Showhint := true;
end;


0
 
LVL 32

Expert Comment

by:ewangoya
ID: 34189034
Oh men

You use two different ini files ?

Disregard my last post, but still clean up the reading as I suggested earlier
0
 

Author Comment

by:pr2501
ID: 34195219
Sorry am confused.

And also with next code form doesn't start.

procedure TForm1.FormCreate(Sender: TObject);
var
  cmp: TShape;
  Lbel : TLabel;
  i: integer;
  IniFile,inilbel,inishape: TiniFile;
begin
  LabelNumber := 0;

  IniFile := TINIFile.Create(ExtractFilePath(Application.Exename) + 'yourinilabel.ini');
  try
    caption:= inilbel.ReadString(Self.Name, 'Caption', Caption);
    LoadBackground( inilbel.ReadString('_global_', 'bitmapfile', '' ) );
    pathstrBitmapFile:=  inilbel.ReadString('_global_', 'bitmapfile', '' );

    n:=0;
    n := inilbel.ReadInteger(Self.Name, 'Label', 0);
    edit2.Text:=inttostr(n);
    //i:=1; remove
    for i := 1 to n do
    begin
      Lbel := TLabel(form1.FindComponent('Label' + IntToStr(i)));
      if Lbel = nil then
      begin
        Lbel := TLabel.Create(Self);
        Lbel.Name := 'Label' + IntToStr(I);
        Lbel.Parent := Self;
        //Lbel.onClick := LabelClick;
        inc(LabelNumber);
        Lbel.Caption := inilbel.ReadString(Self.Name, Lbel.Name + ' Caption', TLabel(Lbel).Caption);
        Lbel.Font.Color := TColor(inilbel.ReadInteger(Self.Name, Lbel.Name + ' Font Color', integer(clWindowText)));
        Lbel.Font.name := inilbel.ReadString(Self.Name, Lbel.Name + ' Font Name', TLabel(Lbel).Font.Name);
        Lbel.Font.Size := inilbel.ReadInteger(Self.Name, Lbel.Name + ' Font Size', TLabel(Lbel).Font.Size);
        Lbel.Top := inilbel.ReadInteger(Self.Name, Lbel.Name + ' Top', Lbel.Top);
        Lbel.Left := inilbel.ReadInteger(Self.Name, Lbel.Name + ' Left', Lbel.Left);
        // Lbel.AutSize := inilbel.ReadBool(Self.Name, Lbel.Name + ' AutoSize', TLabel(Lbel).AutoSize);
        Lbel.Transparent := inilbel.ReadBool(Self.Name, Lbel.Name + ' Transparent', TLabel(Lbel).Transparent);
        Lbel.WordWrap := inilbel.ReadBool(Self.Name, Lbel.Name + ' WordWrap', TLabel(Lbel).WordWrap);
      end;   // if nil
    end;

    FShapeNumber := 0;
    n := inishape.ReadInteger(Self.Name, 'Shapes', 0);
    edit1.Text:=inttostr(n);
    //i:=1; remove
    for i := 1 to n do
    begin
      // if you use TShape as class, you only need to cast once
      cmp := TShape(FindComponent('Shape' + IntToStr(i)));
      if cmp = nil then
      begin
        cmp := TShape.Create(Self);
        cmp.Name := 'Shape' + IntToStr(I);
        cmp.Parent := Self;
        cmp.Tag := FShapeNumber;
        inc(FShapeNumber);
        cmp.Brush.Color := TColor(inishape.ReadInteger(Self.Name, cmp.Name + ' Brush Color', integer(clGreen)));
        cmp.Width := inishape.ReadInteger(Self.Name, cmp.Name + ' Width', cmp.Width);
        cmp.Height := inishape.ReadInteger(Self.Name, cmp.Name + ' Height', cmp.Height);
        cmp.Top := inishape.ReadInteger(Self.Name, cmp.Name + ' Top', cmp.Top);
        cmp.Left := inishape.ReadInteger(Self.Name, cmp.Name + ' Left', cmp.Left);
        cmp.hint := inishape.readString(Self.Name, cmp.Name + ' Hint', '');
        cmp.showhint := inishape.readBool(Self.Name, cmp.Name + ' ShowHint', cmp.hint<>'');

        cmp.onMouseDown := ShapeMouseDown;
        cmp.onMouseMove := ShapeMouseMove;
        cmp.onMouseUp := ShapeMouseUp;
      end;
    end;  // for-loop
  finally
    FreeAndNil(IniFile);
  end;  // try shape

  Application.Showhint := true;
end;
0
 
LVL 24

Expert Comment

by:jimyX
ID: 34195319
You are not following the threads properly, that code has been rejected by its author.

Please try as per my post: 34188257:

http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_26626765.html#34188257
0
 

Author Comment

by:pr2501
ID: 34195329
Withaot error.
0
 

Author Comment

by:pr2501
ID: 34196928
Ok , pleas some more patiention.
Now i have error message whwn i start app:
Acess violation at adress 044c5cc in module ....exe reaad of adress 00000048.

Tell me step by step what to do.
 No need to rush.

thank you
0
 
LVL 25

Expert Comment

by:epasquier
ID: 34197104
As I told you, we NEED to know the source line where the pb occurs. an hexadecimal address is NOT useful at all.
So, now I learn that you get this error when application starts, so put a breakpoint in your main form onCreate event and execute step by step until you identified the last atomic line of YOUR code before the pb raised
0
 
LVL 32

Assisted Solution

by:ewangoya
ewangoya earned 150 total points
ID: 34202009

Heres the correct implementation, you should not get access violation now
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  storeinilabel;
  storeinishape;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  cmp: TShape;
  Lbel : TLabel;
  i, n: integer;
  INIFile: TIniFile;
begin
  FLabelNumber := 0;

  INIFile := TINIFile.Create(ExtractFilePath(Application.Exename) + 'yourinilabel.ini');
  try
    Caption := INIFIle.ReadString(Self.Name, 'Caption', Caption);
    LoadBackground( ReadString('_global_', 'bitmapfile', '' ) );
     pathstrBitmapFile := INIFIle.ReadString('_global_', 'bitmapfile', '' );

    n := INIFIle.ReadInteger(Self.Name, 'Label', 0);
    edit2.Text:=inttostr(n);
    for i := 1 to n do
    begin
      Lbel := TLabel(FindComponent('Label' + IntToStr(i)));
      if Lbel = nil then
      begin
        Lbel := TLabel.Create(Self);
        Lbel.Name := 'Label' + IntToStr(I);
        Lbel.Parent := Self;
        //Lbel.onClick := LabelClick;
        inc(FLabelNumber);
        Lbel.Caption := INIFIle.ReadString(Self.Name, Lbel.Name + ' Caption', Lbel.Caption);
        Lbel.Font.Color := TColor(INIFIle.ReadInteger(Self.Name, Lbel.Name + ' Font Color', integer(clWindowText)));
        Lbel.Font.name := INIFIle.ReadString(Self.Name, Lbel.Name + ' Font Name', Lbel.Font.Name);
        Lbel.Font.Size := INIFIle.ReadInteger(Self.Name, Lbel.Name + ' Font Size', Lbel.Font.Size);
        Lbel.Top := INIFIle.ReadInteger(Self.Name, Lbel.Name + ' Top', Lbel.Top);
        Lbel.Left :=INIFIle. ReadInteger(Self.Name, Lbel.Name + ' Left', Lbel.Left);
        Lbel.Transparent := INIFIle.ReadBool(Self.Name, Lbel.Name + ' Transparent', Lbel.Transparent);
        Lbel.WordWrap :=INIFIle. ReadBool(Self.Name, Lbel.Name + ' WordWrap', Lbel.WordWrap);
      end;
    end;
  finally
    FreeAndNil(INIFile);
  end;

  FShapeNumber := 0;
  INIFile := TINIFile.Create(ExtractFilePath(Application.Exename) + 'yourinishape.ini');
  try
    n := INIFile.ReadInteger(Self.Name, 'Shapes', 0);
    edit1.Text:=inttostr(n);
    for i := 1 to n do
    begin
      cmp := TShape(FindComponent('Shape' + IntToStr(i)));
      if cmp = nil then
      begin
        cmp := TShape.Create(Self);
        cmp.Name := 'Shape' + IntToStr(I);
        cmp.Parent := Self;
        cmp.onMouseDown := ShapeMouseDown;
        cmp.onMouseMove := ShapeMouseMove;
        cmp.onMouseUp := ShapeMouseUp;
        cmp.Tag := FShapeNumber;
        inc(FShapeNumber);
        cmp.Brush.Color := TColor(INIFile.ReadInteger(Self.Name, cmp.Name + ' Brush Color', integer(clGreen)));
        cmp.Width := INIFile.ReadInteger(Self.Name, cmp.Name + ' Width', cmp.Width);
        cmp.Height := INIFile.ReadInteger(Self.Name, cmp.Name + ' Height', cmp.Height);
        cmp.Top := INIFile.ReadInteger(Self.Name, cmp.Name + ' Top', cmp.Top);
        cmp.Left := INIFile.ReadInteger(Self.Name, cmp.Name + ' Left', cmp.Left);
        cmp.hint := INIFile.readString(Self.Name, cmp.Name + ' Hint', '');
        cmp.showhint := INIFile.readBool(Self.Name, cmp.Name + ' ShowHint', cmp.Hint <> '');
      end;
    end;
  finally
    FreeAndNil(INIFile);
  end;

  Application.Showhint := true;
end;

procedure TForm1.ShapeMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  // i now make a difference between selecting and dragging a shape
  // this make it possible to keep a selection and that is usefull for the speedbutton function
  if Assigned(Sender) and (Sender is TShape) then
  begin
   FSelectedShape := TShape(Sender); // Might be usefull for other treatments
      //ShapeMenu: TPopupMenu;
   if ssRight in Shift Then
   begin
     PopupMenu1.Popup(Mouse.CursorPos.X,Mouse.CursorPos.Y);
     Exit;
   end;
   if ssLeft in Shift then begin
      // set the last clicked shape with right button
      // get its start position relative to position of mouse when the click occurred
      _Pos.X := FSelectedShape.Left-Mouse.CursorPos.X;
      _Pos.Y := FSelectedShape.Top-Mouse.CursorPos.Y;
      FDragShape := FSelectedShape;
    end;
  end;
end;

procedure TForm1.ShapeMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
  // only dragging with left mouse button
  if Not (ssLeft in Shift) then
    FDragShape := nil;
  if Not Assigned(FDragShape) then
    Exit;
  // Don't use X & Y directly as they are relative to the object, which is moving
  FDragShape.Left := _Pos.X + Mouse.CursorPos.X;
  FDragShape.Top := _Pos.Y + Mouse.CursorPos.Y;
  if Assigned(FSelectedShapelabel) then
  begin
    FSelectedShapelabel.Left:= _Pos.X + Mouse.CursorPos.X;
    FSelectedShapelabel.Top := _Pos.Y + Mouse.CursorPos.Y - 12;
  end;
end;

procedure TForm1.ShapeMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  //finish the drag
  FDragShape := nil;
end;

procedure TForm1.storeinilabel;
var
  cmplabel: TLabel;
  j, LabelCount: integer;
  E: TIniFile;
  FileName: string;
begin
  FileName := IncludeTrailingPathDelimiter(ExtractFilePath(Application.Exename)) + 'yourinilabel.ini';
  E := TINIFile.Create(FileName);
  try
    E.EraseSection(Self.Name);
    E. WriteString(Self.Name, 'Caption', Caption);
    E.WriteString('_global_', 'bitmapfile', pathstrBitmapFile) ;

    LabelCount := 0;
    for J := 0 to ComponentCount - 1 do
      if Components[J] is TLabel then
      begin
        cmplabel := TLabel(Components[J]);
        Inc(LabelCount);
        E.WriteInteger(Self.Name, cmpLabel.Name + ' Top', cmpLabel.Top);
        E.WriteInteger(Self.Name, cmpLabel.Name + ' Left', cmpLabel.Left);
        E.WriteString(Self.Name, cmpLabel.Name + ' Caption', cmpLabel.Caption);
      end;
    E.WriteInteger(Self.Name, 'Label', LabelCount);
  finally
    FreeAndNil(E);
  end ;
end;

procedure TForm1.storeinishape;
var
  cmpshape: TShape;
  I, ShapeCount: integer;
  F: TIniFile;
  FileName: string;
begin
  FileName := IncludeTrailingPathDelimiter(ExtractFilePath(Application.Exename)) + 'yourinishape.ini';
  F := TINIFile.Create(FileName);
  try
    F.WriteString('APPLICATION','NAME',ExtractFileName(Application.ExeName));
    F.WriteString('APPLICATION','PATH',ExtractFilePath(Application.ExeName));
    F.WriteString('APPLICATION','INI', ExtractFilePath(Application.ExeName) + 'app.ini');

    ShapeCount := 0;
    for I := 0 to ComponentCount - 1 do
      if Components[I] is TShape then
      begin
        cmpshape := TShape(Components[I]);
        Inc(ShapeCount);
        F.WriteInteger(Self.Name, cmpshape.Name + ' Brush Color', cmpshape.Brush.Color);
        F.WriteInteger(Self.Name, cmpshape.Name + ' Width', cmpshape.Width);
        F.WriteInteger(Self.Name, cmpshape.Name + ' Height', cmpshape.Height);
        F.WriteInteger(Self.Name, cmpshape.Name + ' Top', cmpshape.Top);
        F.WriteInteger(Self.Name, cmpshape.Name + ' Left', cmpshape.Left);
        F.WriteString(Self.Name, cmpshape.Name + ' Hint', cmpshape.Hint);
        F.WriteBool(Self.Name, cmpshape.Name + ' ShowHint', cmpshape.Showhint);
      end;
    F.WriteInteger(Self.Name, 'Shapes', ShapeCount);
  finally
    FreeAndNil(F);
  end;
end;

Open in new window

0
 

Author Comment

by:pr2501
ID: 34203060
ewangoya:
Now i can move shape1 after restarting of app. But when i try to create another TShape i get message that shape1 already exist.

epasquier:
using debugging i have got problem in line : if DirectoryExists( MySelectedFolder+'\'+strShapeName)
belove:
procedure TForm1.imeClick(Sender: TObject);
   var
   a:integer;
begin
  strShapeName := '';
  //  look for path
  MySelectedFolder:=  ExtractPath(Form1.caption);
  // check if something is selected
  if Assigned(FSelectedShape) then begin
        strShapeName := InputBox('',hej oj', strShapeName);
      FSelectedShape.Hint:=strShapeName;
      FSelectedShape.Brush.Color:= clgreen;
      iShapeIndex:=n+1;
      a:= iShapeIndex ;
      FSelectedShape.Name := 'shape' + inttostr(iShapeIndex);
if DirectoryExists( MySelectedFolder+'\'+strShapeName) then begin  ShowMessage( MySelectedFolder+'\'+strShapeName + '  some same') ;
      exit;
      end  else
      CreateDir( MySelectedFolder+'\'+strShapeName);
      //create *.txt
      makfile( MySelectedFolder+'\'+strShapeName+'\'+strShapeName+'.txt');
  end;
  if Assigned(FSelectedShapelabel) then begin
     FSelectedShapelabel.Caption:= strShapeName;
     FSelectedShapelabel.Name:= 'label'  + inttostr(iShapeIndex);
  end;
  inc(n);
end;
0
 
LVL 25

Expert Comment

by:epasquier
ID: 34203428
you should use FShapeNumber instead of iShapeIndex:=n+1;
n is declared in your FormCreate, I don't know how you managed to compile OR you also declared that variable as global (horror). Besides, you use n both for labels and shapes. Difficult to understand what the heck is going on...
I don't know where you declared iShapeIndex, but it seems redundant with FShapeNumber

Globally, I found that your system of naming shapes and label with an index that must be continuous is a bit of a mess. What if you create 3 shapes 0..2 and you later delete the second ? you will have a hole in your serie that your app cannot manage propertly. You should store the unique ID incremented each time you create a new element.
The same could be said about your multiple ini files. You could well have only ONE ini file for all your labels and shapes, and even your app parameters. That's what sections are for.

[SHAPES]
COUNT=2          // Nb of shapes actually stored in INI
NEXT_INDEX=3   // global unique index used on next creation

[SHAPE_0] // here, the index is ONLY used with COUNT and not related to the name of label 
Name=shape0
Top=...

[SHAPE_1] // that is what happens if Shape1 has been deleted
Name=shape2
Top=...

[LABELS]
COUNT=2
NEXT_INDEX=2

[LABEL_0] 
Name=Label0
Caption=...

Open in new window

procedure TForm1.imeClick(Sender: TObject);
begin
 strShapeName := '';
 //  look for path
 MySelectedFolder:=  ExtractPath(Form1.caption);
 // check if something is selected
 if Assigned(FSelectedShape) then 
  begin
   strShapeName := InputBox('',hej oj', strShapeName);
   FSelectedShape.Hint:=strShapeName;
   FSelectedShape.Brush.Color:= clgreen;
   Inc(FShapeNumber);
   FSelectedShape.Name := 'shape' + inttostr(FShapeNumber);
   if DirectoryExists( MySelectedFolder+'\'+strShapeName) then 
    begin  
     ShowMessage( MySelectedFolder+'\'+strShapeName + '  some same') ;
     exit;
    end;
   CreateDir( MySelectedFolder+'\'+strShapeName);
   //create *.txt
   makfile( MySelectedFolder+'\'+strShapeName+'\'+strShapeName+'.txt');
  end;
 if Assigned(FSelectedShapelabel) then 
  begin
   FSelectedShapelabel.Caption:= strShapeName;
   FSelectedShapelabel.Name:= 'label'  + inttostr(iShapeIndex);
  end;
 inc(n); // what to do with that ?
end;

Open in new window

0
 

Author Comment

by:pr2501
ID: 34228363
It looks that i have to do it all  from the start.

0
 
LVL 32

Expert Comment

by:ewangoya
ID: 34230125
If you want to do it well this time, use xml instead of ini files
You will be much better off
0
 
LVL 25

Accepted Solution

by:
epasquier earned 200 total points
ID: 34230818
Well, it is not a problem of using Ini or XML to actually store data, it is a matter of application architecture to be able to create/delete components at will without limitations about names and counts.

It is true that XML is better to allow easier edition of the file in a text editor. But that is probably not an advantage here, and XML is a lot more difficult to use (programmatically) than Ini files.

Try to find a better way to store collections of dynamic components in your application, without thinking too much of HOW you will save those collections. That is not what matters, and your application should be totally independant of that HOW. So you could well start with a Ini-based solution because you should master it better now, and later use XML if you really want to. Or plain binary files with records, or stream-based variable binary files. Whatever suits your needs. XML is NOT always the best option.
0
 

Author Comment

by:pr2501
ID: 34236683
Thank you .
It's time for me to start working more serious.
0

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Working with hours 3 64
Error E2158 compiling with Delphi XE10 Seattle 2 112
Dev express lookupcombo 3 34
RESTRequest Parameter 4 42
In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
A short tutorial showing how to set up an email signature in Outlook on the Web (previously known as OWA). For free email signatures designs, visit https://www.mail-signatures.com/articles/signature-templates/?sts=6651 If you want to manage em…

809 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question