• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 673
  • Last Modified:

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

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
pr2501
Asked:
pr2501
  • 9
  • 8
  • 6
  • +1
3 Solutions
 
jimyXCommented:
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
 
Ephraim WangoyaCommented:

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
 
epasquierCommented:
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
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
pr2501Author Commented:
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
 
jimyXCommented:
Can you also attach the code of saving the Shape to the ini ?
0
 
pr2501Author Commented:
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
 
epasquierCommented:
can you do the modifications we talked about and tell us exactly on which line it raise an exception ?
0
 
pr2501Author Commented:
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
 
epasquierCommented:
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
 
jimyXCommented:
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
 
epasquierCommented:
what have you changed exactly ?
0
 
Ephraim WangoyaCommented:

>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
 
jimyXCommented:
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
 
epasquierCommented:
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
 
Ephraim WangoyaCommented:
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
 
Ephraim WangoyaCommented:
Oh men

You use two different ini files ?

Disregard my last post, but still clean up the reading as I suggested earlier
0
 
pr2501Author Commented:
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
 
jimyXCommented:
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
 
pr2501Author Commented:
Withaot error.
0
 
pr2501Author Commented:
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
 
epasquierCommented:
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
 
Ephraim WangoyaCommented:

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
 
pr2501Author Commented:
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
 
epasquierCommented:
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
 
pr2501Author Commented:
It looks that i have to do it all  from the start.

0
 
Ephraim WangoyaCommented:
If you want to do it well this time, use xml instead of ini files
You will be much better off
0
 
epasquierCommented:
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
 
pr2501Author Commented:
Thank you .
It's time for me to start working more serious.
0

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

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

  • 9
  • 8
  • 6
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now