1

Hi I have just completed a component which implements a Table search on typing in an edit box and showing the results in a drop down dbCtrlGrid. It compiles and installs without any problem. But when placed on a form Delphi (7) I get a Stack Overflow save your work and restart Delphi. I cannot debug it as it is not on the form so can anyone help please?

unit QueryPnl;

interface

uses WinTypes, WinProcs, Messages, SysUtils, Classes, Controls,
Forms, Graphics, Extctrls, Eedit, Stdctrls, ABSMain,
Db, DBCtrls, EDBEdit, dbcgrids;

type
  TQueryPanel = class(TPanel)
   private
    Addressmem : TDBMemo;
    Display : TDBCtrlGrid;
    DsQ1 : TDataSource;
    Head : TLabel;
    FDbase : TABSDatabase;
    FTableName : string;
    FOnInTextChange : TNotifyEvent;
    procedure AutoInitialize;
    procedure AutoDestroy;

   protected
    InText : TEedit;
    NmText : TEDBEdit;
    NumText : TEDBEdit;
    Q1 : TABSQuery;
    procedure InTextChange(Sender : TObject); overload;
    procedure DoEnter; override;
    procedure DoExit; override;
    procedure Click; override;
    procedure KeyPress(var Key : Char); override;
    procedure Loaded; override;
    procedure Paint; override;
    function GetFDbase : TABSDatabase;
    procedure SetFDbase(Value : TABSDatabase);
    function GetFTableName : string;
    procedure SetFTableName(Value : string);
    
   public
    procedure InTextChange;overload;
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

   published
    property OnClick;
    property OnDblClick;
    property OnDragDrop;
    property OnEnter;
    property OnExit;
    property OnKeyDown;
    property OnKeyPress;
    property OnKeyUp;
    property OnMouseDown;
    property OnMouseMove;
    property OnMouseUp;
    property OnResize;
    property DBase : TABSDatabase read FDBase write SetFDBase;
    property TableName : String read FTableName write SetFTableName;
    property OnInTextChange : TNotifyEvent read FOnInTextChange write FOnInTextChange;
    
  end;
  
procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Data Controls', [TQueryPanel]);
end;

procedure TQueryPanel.AutoInitialize;
begin
  Addressmem.Parent := Display;
  with Addressmem do
    begin
      Left := 2;
      Top := 50;
      Width := 115;
      Height := 50;
      DataField := 'Address';
      TabOrder := 1;
    end;
  Display.Parent := Self;
  with Display do
    begin
      DataSource:=DsQ1;
      Left := 0;
      Top := 54;
      Width := 138;
      Height := 315;
      Color := $00E8DBCE;
      PanelHeight := 105;
      PanelWidth := 121;
      ParentColor := False;
      TabOrder := 2;
    end;
  DsQ1.DataSet:=Q1;
  Head.Parent := Self;
  with Head do
    begin
      Left := 1;
      Top := 1;
      Width := 136;
      Height := 13;
      Align := alTop;
      Alignment := taCenter;
      Caption := 'Quick Name Search';
      Font.Charset := DEFAULT_CHARSET;
      Font.Color := clRed;
      Font.Height := -12;
      Font.Name := 'MS Sans Serif';
      Font.Style := [fsBold];
      ParentFont := False;
    end;
  InText.Parent := Self;
  with InText do
    begin
      Left := 0;
      Top := 25;
      Width := 121;
      Height := 21;
      TabOrder := 0;
      OnChange := InTextChange;
      UpCaseFirst := True;
      ColorOnFocus := clYellow;
    end;
  NmText.Parent := Display;
  with NmText do
    begin
      Left := 2;
      Top := 8;
      Width := 115;
      Height := 21;
      DataField := 'Name';
      Font.Charset := DEFAULT_CHARSET;
      Font.Color := clWindowText;
      Font.Height := -11;
      Font.Name := 'MS Sans Serif';
      Font.Style := [fsBold];
      ParentFont := False;
      TabOrder := 0;
    end;
  NumText.Parent := Display;
  with NumText do
    begin
      Left := 1;
      Top := 29;
      Width := 115;
      Height := 21;
      DataField := 'Number';
      Font.Style := [fsBold];
      TabOrder := 2;
    end;
  Q1.DatabaseName:=FDBase.Name;
  Q1.RequestLive:=True;
end;

procedure TQueryPanel.AutoDestroy;
begin
  Addressmem.Free;
  Display.Free;
  DsQ1.Free;
  Head.Free;
  InText.Free;
  NmText.Free;
  NumText.Free;
  Q1.Free;
end;

procedure TQueryPanel.DoEnter;
begin
  inherited DoEnter;
  Height := 370;
end;

procedure TQueryPanel.DoExit;
begin
  inherited DoExit;
  Height := 55;
end;

function TQueryPanel.GetFDbase : TABSDatabase;
begin
Result := FDbase;
end;

procedure TQueryPanel.SetFDBase(Value : TABSDatabase);
begin
  FDBase := Value;
  // Other code to do when selecting the database
end;

function TQueryPanel.GetFTableName : string;
begin
  Result := FTableName;
end;

procedure TQueryPanel.SetFTableName(Value : String);
begin
  FTableName := Value;
  // Other code to do when selecting the table
end;

procedure TQueryPanel.InTextChange(Sender : TObject);
begin
  if Assigned(FOnInTextChange) then
  FOnInTextChange(Sender);
  Q1.Close;
  Q1.SQL.Text:='select * from '+FTableName+' where Name like :nem';
  Q1.ParamByName('nem').asString:=InText.Text;
  Q1.Open;
end;

procedure TQueryPanel.Click;
begin
  inherited Click;
end;

procedure TQueryPanel.KeyPress(var Key : Char);
const
  TabKey = Char(VK_TAB);
  EnterKey = Char(VK_RETURN);
begin
  inherited KeyPress(Key);
end;

constructor TQueryPanel.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  Addressmem := TDBMemo.Create(Self);
  Display := TDBCtrlGrid.Create(Self);
  DsQ1 := TDataSource.Create(Self);
  InText := TEedit.Create(Self);
  Head := TLabel.Create(Self);
  NmText := TEDBEdit.Create(Self);
  NumText := TEDBEdit.Create(Self);
  Q1 := TABSQuery.Create(Self);
  AutoInitialize;
end;

destructor TQueryPanel.Destroy;
begin
  inherited Destroy;
end;

procedure TQueryPanel.InTextChange;
begin
//
end;

procedure TQueryPanel.Loaded;
begin
  inherited Loaded;
end;

procedure TQueryPanel.Paint;
begin
  inherited Paint;
end;
end.
3
  • 1
    "I cannot debug it as it is not on the form" - you can debug it, actually. You can run 2 instances of the IDE, where the debugger in the 1st instance is attached to the 2nd instance. Then you can debug what your component code does at design-time in the 2nd instance and see what is actually crashing. Otherwise, using just 1 instance, you can create your component object in code instead of using the Form Designer, and then you can debug your component code at run-time. Commented Dec 17, 2020 at 16:35
  • Please don't change your original question to implement the suggested fixes given in answers. If you do that, readers of this Q&A will be very confused, since the answers no longer match the question. Stack Overflow is a strict Q&A site (with focus on building a resource for future readers), not a forum or support site. Commented Dec 17, 2020 at 18:56
  • Sorry but I followed Germán Estévez' comment in updating my code on the question Commented Dec 17, 2020 at 22:11

3 Answers 3

3

Many times, StackOverflow errors are due to an infinite recursion.
I think the code of these two procedures causes that:

procedure SetDBase(Value : TABSDatabase);
procedure SetTableName(Value : String);

Use Field like FDBase and FTableName to store the values (for example).
The 2 methods are causing the Set method to be called again infinitely.

Sign up to request clarification or add additional context in comments.

8 Comments

Thank you but I am afraid I still get the same error
@dcs Update the code on the question. To see the changes that you have made.
Sorry I just did
You solved your existing problem. Now your error is probably coming from somewhere else.
@dcs You didn't change anything - you just renamed the properties. You need backing fields to operate on to store the state in question. Your properties are still just setting themselves, which still leads to an infinite loop.
|
1

In the private section, add this:

   FDBase : TABSDataBase;
   FTableName : String;

In the published section, add:

   property DBase : TABSDataBase read FDBase write SetDBase;
   property TableName : String read FTableName write SetTableName;

In the implementation, write:

procedure TQueryPanel.SetDBase(Value : TABSDatabase);
begin
  FDBase := Value;
  // Other code to do when selecting the database
end;

procedure TQueryPanel.SetTableName(Value : String);
begin
  FTableName := Value;
  // Other code to do when selecting the table
end;

Where I put comments "Other code...", if there is nothing to do, you don't need the setter at all.

Please keep attention that fields begin by letter F and properties don't.

2 Comments

Changed the code as suggested but now I am getting an Access Violation
OK, you have another error. Please let us know where exactly you get the Access Violation (To debug your component running in the IDE, debug your component package (it is a DLL actually) and set bds.exe as the host application. When you start debugging, a second instance of the IDE will start. Make it go to the AV).
1

I tracke the error - it was in the TQueryPanel.AutoInitialize; I guess that the line

Q1.DatabaseName:=FDBase.Name;

was in the wrong place so I put in

procedure TQueryPanel.SetDbase(Value : TABSDatabase);
begin
  FDbase:= Value;
  Q1.DatabaseName:=FDBase.DatabaseName;
end;

and it works fine now.Thank you everyone for your help and suggestions

Actually it doesn't. The first panel of the DBCtrlGrid is fine but apparently you have to have the DBCtrlGrid.Panel as parent which is reserved and cannot be accessed. Shame it seemed an ideal solution in a limited space.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.