Solved

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

Posted on 2010-11-19
28
636 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
 

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
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
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

Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

Join & Write a Comment

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…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…
This tutorial demonstrates a quick way of adding group price to multiple Magento products.

762 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

Need Help in Real-Time?

Connect with top rated Experts

21 Experts available now in Live!

Get 1:1 Help Now