Обертка для TList и форма.

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Обертка для TList и форма.

Сообщение CynicRus » 10.07.2012 20:37:20

Ещё раз приветствую уважаемых форумчан. Пишу дизайнер форм для одного скриптового языка, соответственно случилась необходимость прикрутить к этому делу небольшой редактор контролов. Я пошел следующим путем:
1) Завел структуру TSimbaComponent, описывающую компонент существующий в скриптовом языке:
Код: Выделить всё
type
  TSimbaComponent = record
    tp: integer;
    caption: string;
    left,top,width,heigth: integer;
    fontcolor: TColor;
    fontname: string;
    fontsize: integer;
  end;
  type
  PSimbaComponent = ^TSimbaComponent;                               

2) Написал класс-обертку для TList Для удобной работы с моей структурой:
Код: Выделить всё
type

{ TSimbaComponentList }

TSimbaComponentList = class
  private
    FList: TList; // Simba components storage
  public
  constructor Create;
  destructor Destroy; override;
  function AddItem(Item: TSimbaComponent): Integer;
  procedure RemoveItem(ItemIndex: Integer);
  function GetComponent(Idx: integer): TSimbaComponent;
  function GetComponentPtr(Idx: integer): PSimbaComponent;
  function Count: integer;
end;

implementation

{ TSimbaComponentList }

constructor TSimbaComponentList.Create;
begin
  FList := TList.Create;//create storage
  inherited Create;
end;

destructor TSimbaComponentList.Destroy;
begin
  FList.Free; //free storage
  inherited Destroy;
end;

function TSimbaComponentList.AddItem(Item: TSimbaComponent): Integer;
var
p: PSimbaComponent;
begin
  GetMem(p, SizeOf(Item)); // independently allocate memory
  Move(Item, p^, SizeOf(Item));
  Result := FList.Add(p); // simply redirect a call
end;

procedure TSimbaComponentList.RemoveItem(ItemIndex: Integer);
begin
  FreeMem(FList[ItemIndex]); // freememory
  FList.Delete(ItemIndex);
end;

function TSimbaComponentList.GetComponent(Idx: integer): TSimbaComponent;
begin
  FillChar(Result, SizeOf(TSimbaComponent), #0);
  Result := TSimbaComponent(FList.Items[Idx]^); // redirect a call and convert it to TBitmap
end;

function TSimbaComponentList.GetComponentPtr(Idx: integer): PSimbaComponent;
begin
  Result := FList.Items[Idx];//redirect a call
end;

function TSimbaComponentList.Count: integer;
begin
  Result := FList.Count;
end;                             

3) Написал процедуру, забирающую у контрола необходимые свойства и присваивающую их структуре:
Код: Выделить всё
function TCompForm.ComponentToSimba(cmp: TControl): TSimbaComponent;
var
   smb: TSimbaComponent;
begin
   smb.caption:=cmp.Caption;
   smb.top:=cmp.Top;
   smb.width:=cmp.Width;
   smb.left:=cmp.Left;
   smb.heigth:=cmp.Height;
   smb.tp:=GetControlType(cmp);
   smb.fontcolor:=cmp.Font.Color;
   smb.fontname:=cmp.Font.Name;
   smb.fontsize:=cmp.Font.Size;
   result:=smb;
end;

4) На главной форме разместил стринггрид, и заполняю его:
Код: Выделить всё
procedure TCompForm.AddToStringGrid(cmp: TControl);
var
   smb: TSimbaComponent;
begin
   smb:=ComponentToSimba(cmp);
  CompList.AddItem(smb);
  with StringGrid1 do begin
    Cells[1,1]:=cmp.ClassName;
    Cells[1,2]:=smb.caption;
    Cells[1,3]:=IntToStr(smb.top);
    Cells[1,4]:=IntToStr(smb.left);
    Cells[1,5]:=IntToStr(smb.width);
    Cells[1,6]:=IntToStr(smb.heigth);
    Cells[1,7]:=smb.fontname;
    cells[1,8]:=IntToStr(smb.fontsize);
    Cells[1,9]:=ColorToStr(smb.fontcolor);
  end;
end;                   

5) Форма 2 создается в рантайме, и располагается на панели формы 1. После выбора контрола на первой форме, он располагается на форме 2, его свойства пишуться в структуру, затем структура отображается в гриде. Но только если выбран контрол, при простом клике на форму - я ловлю категорический сегфолт и уже весь мозг сломал, как же мне это вылечить. В отладчике смотрел - как я понимаю, косяк со свойством контрола Tag. Но как мне быть - придумать пока не могу-(
Код создания контрола
Код: Выделить всё
procedure TDsgnForm.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  _comp := CreateComponent(Sender, X, Y);
  if (_comp.Tag <> 0) then
  CompForm.AddToStringGrid(_comp) else
    CompForm.AddToStringGridEx(CompForm.CompList.GetComponent(0),_comp);
end; 

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

Добавлено спустя 2 минуты 7 секунд:
PS: сегфолт ловлю на строке
Код: Выделить всё
if (_comp.Tag <> 0) then
если её убрать, то - на строке 2788 модуля control.inc, и выглядит она
Код: Выделить всё
if TMethod(@Self.GetTextBuf).Code = Pointer(@TControl.GetTextBuf)
CynicRus
постоялец
 
Сообщения: 106
Зарегистрирован: 28.06.2012 14:31:11

Re: Обертка для TList и форма.

Сообщение Vadim » 11.07.2012 05:39:12

_comp - это у Вас что такое?
На каком основании Вы уверены, что он у Вас создался?
Vadim
долгожитель
 
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

Re: Обертка для TList и форма.

Сообщение CynicRus » 11.07.2012 09:40:37

_comp - TControl, глобальная переменная.

Почему уверен?
Вот:
Код: Выделить всё
function TDsgnForm.CreateComponent(Sender: TObject; X, Y: Integer): TControl;
var
  comp:TComponent;
  none:Boolean;
  CreateClass:TComponentClass;
  cname:String;
  pInfo: PTypeInfo;
  //----------------------------------------------------------
  function __CreateComp():TComponent;
  begin
    Result := nil;
    if Assigned(CreateClass) then begin
      comp := CreateClass.Create(Self);
      pInfo := comp.ClassInfo;
      cname := pInfo^.Name;
      if (comp is TWinControl) then begin
        TWinControl(comp).ParentWindow := TWinControl(Sender).Handle;
        TWinControl(comp).Parent := TWinControl(Sender);
        TWinControl(comp).Name := cname + IntToStr(_ControlsCreated);
        TWinControl(comp).Left := X;
        TWinControl(comp).Top := Y;
        comp.Tag:=_ControlsCreated;
      end
      else if (comp is TControl) then begin
        TControl(comp).Parent := TWinControl(Sender);
        TControl(comp).Name := cname + IntToStr(_ControlsCreated);
        TControl(comp).Left := X;
        TControl(comp).Top := Y;
        comp.Tag:=_ControlsCreated;
      end;
      _ControlsCreated := _ControlsCreated + 1;
      Result := comp;
    end;
  end;
  //----------------------------------------------------------
  procedure __UpButton();
  begin
    if Assigned(CompForm.ButtonDown) then begin
      TToolBar(CompForm.ButtonDown.Parent).Buttons[0].Down := True;
      CompForm.ButtonDown := nil;
    end;
  end;
  //----------------------------------------------------------
  procedure __TrackEvent();
  begin
    if Assigned(comp) then begin
      THControl(comp).OnMouseDown :=@FormMouseDown;
    end;
  end;
begin
  comp := nil;
  none := False;
  CreateClass := nil;
  if (CompForm.ButtonIndex <> -1) then begin
      CreateClass := CompForm.ControlsClassPStd[CompForm.ButtonIndex];
    comp := __CreateComp();
    __UpButton();
    __TrackEvent();
  end
  else begin
    none := True;
  end;
  if (none) then begin
    if (Sender <> Self) then begin
      sor.SelectControl := TControl(Sender);
    end
    else begin
      sor.Selected := False;
      sor.SelectControl := nil;
    end;
  end
  else begin
    sor.SelectControl := TControl(comp);
  end;
  Result := TControl(comp);
end;                         
CynicRus
постоялец
 
Сообщения: 106
Зарегистрирован: 28.06.2012 14:31:11

Re: Обертка для TList и форма.

Сообщение Vadim » 11.07.2012 14:00:03

Ваша ошибка - это обращение к тому, чего нет. Поскольку единственный элемент в строке с ошибкой это _comp, следовательно, он у Вас и отсутствует. Предварительную проверку на существование Вы не производите, а зря. Было бы лучше делать так:
Код: Выделить всё
If Assign(_comp) Then
  //Делаете то, что хотели делать с компонентом
Else
  MessageBox('ФигВам!');
Vadim
долгожитель
 
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

Re: Обертка для TList и форма.

Сообщение CynicRus » 12.07.2012 10:25:13

Спасибо!
CynicRus
постоялец
 
Сообщения: 106
Зарегистрирован: 28.06.2012 14:31:11

Re: Обертка для TList и форма.

Сообщение B4rr4cuda » 13.07.2012 22:22:55

CynicRus, спасибо за наводку.. этот скриптовик - неплохая обертка и пример работы с паскальскриптом.
Аватара пользователя
B4rr4cuda
энтузиаст
 
Сообщения: 693
Зарегистрирован: 28.12.2007 07:48:35


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 256

Рейтинг@Mail.ru
cron