【问题标题】:Stack Overflow error on adding component to form将组件添加到表单时出现堆栈溢出错误
【发布时间】:2021-03-28 03:46:21
【问题描述】:

您好,我刚刚完成了一个组件,它实现了在编辑框中键入并在下拉 dbCtrlGrid 中显示结果的表格搜索。它编译和安装没有任何问题。但是当放置在 Delphi (7) 表单上时,我会得到一个 Stack Overflow 保存您的工作并重新启动 Delphi。我无法调试它,因为它不在表单上,​​所以有人可以帮忙吗?

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.

【问题讨论】:

  • "我无法调试它,因为它不在表单上" - 实际上你可以调试它。您可以运行 IDE 的 2 个实例,其中第一个实例中的调试器附加到第二个实例。然后,您可以在第二个实例中在设计时调试您的组件代码所做的事情,并查看实际崩溃的情况。否则,仅使用 1 个实例,您可以在代码中创建组件对象,而不是使用表单设计器,然后您可以在运行时调试组件代码。
  • 请不要更改您的原始问题以实施答案中给出的建议修复。如果你这样做了,这个问答的读者会很困惑,因为答案不再与问题匹配。 Stack Overflow 是一个严格的问答网站(专注于为未来的读者构建资源),而不是论坛或支持网站。
  • 抱歉,我按照 Germán Estévez 的评论更新了我的问题代码

标签: delphi


【解决方案1】:

我跟踪错误 - 它在 TQueryPanel.AutoInitialize 中; 我猜那行

Q1.DatabaseName:=FDBase.Name;

放错地方了

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

现在可以正常使用了。谢谢大家的帮助和建议

实际上并没有。 DBCtrlGrid 的第一个面板很好,但显然您必须将 DBCtrlGrid.Panel 作为父级保留且无法访问。可惜它似乎是有限空间内的理想解决方案。

【讨论】:

    【解决方案2】:

    private 部分中,添加以下内容:

       FDBase : TABSDataBase;
       FTableName : String;
    

    published 部分,添加:

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

    implementation,写:

    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;
    

    我把cmets“Other code...”的地方放了,如果没有什么可做的,你根本就不需要setter。

    请注意字段以字母 F 开头,而属性则不要。

    【讨论】:

    • 按照建议更改了代码,但现在我遇到了访问冲突
    • 好的,你有另一个错误。请让我们知道您在哪里得到访问冲突(要调试在 IDE 中运行的组件,请调试您的组件包(实际上是一个 DLL)并将 bds.exe 设置为主机应用程序。当您开始调试时,第二个实例IDE的将启动。让它去AV)。
    【解决方案3】:

    很多时候,StackOverflow 错误是由于无限递归造成的。
    我认为这两个程序的代码导致:

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

    使用 FDBaseFTableName 等字段来存储值(例如)。
    这两种方法导致 Set 方法被无限调用。

    【讨论】:

    • 谢谢,但我恐怕还是会遇到同样的错误
    • @dcs 更新问题的代码。查看您所做的更改。
    • 对不起,我刚刚做了
    • 您解决了现有问题。现在您的错误可能来自其他地方。
    • @dcs 你没有改变任何东西——你只是重命名了属性。您需要支持字段来操作以存储相关状态。您的属性仍然只是设置自己,这仍然会导致无限循环。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-28
    • 2014-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-30
    相关资源
    最近更新 更多