【问题标题】:Refresh DBGrid from another form in delphi从delphi中的另一个表单刷新DBGrid
【发布时间】:2015-05-10 10:01:39
【问题描述】:

我刚刚开始学习 Delphi,但遇到了问题。我会从另一种形式刷新 DBGrid。我的代码:

表格1:

unit uForm1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, DB, ADODB, Grids, DBGrids, StdCtrls;

type
  TForm1 = class(TForm)
    btnAdd: TButton;
    grid: TDBGrid;
    ADOQuery1: TADOQuery;
    DataSource1: TDataSource;
    procedure btnAdd(Sender: TObject);
  private
  public
       constructor Create(Owner:TComponent); overload;
  end;

var
  form1: TForm1;

implementation

uses uForm2, uDbOperations;

{$R *.dfm}

procedure TForm1.btnAddClick(Sender: TObject);
var
  frm : TForm2;
begin
  frm := TForm2.Create(form1);
  frm.ShowModal;
  frm.Free;
end;

表格2:

unit uForm2;
procedure TForm2.btnAddClick(Sender: TObject);
var
  query : string;
begin
       query := 'Insert into Employees(Name) Values('''+txtName.Text+''');';
       DbOperations.InsertOrUpdate(query, ADOQuery1);
        ModalResult := mrCancel;
        //And this here I'd refresh grid on form1           
end;
end.

在form2中添加记录后如何刷新form1中的dbgrid?我尝试了很多方法,但没有成功。我知道在 C# 中需要在构造函数中传递引用,但是 delphi 怎么做?

【问题讨论】:

  • 如果 DBgrid 连接到 DataSoource1,则在关闭模态表单后只需 DataSource1.DataSet.Refresh
  • @TLama 我编辑我的评论。我看不到谁是 DBGrid 数据源
  • @Val,你是对的!我已经删除了我的评论。它们将是单独的组件,这很好(尽管它们都具有相同的名称,但事实并非如此)。所以,我只是将它添加到 centralize 数据集组件中,您可以使用数据模块而不是表单。还要考虑如果用户将x'; DROP TABLE Employees; 输入到您的txtName 控件中会发生什么。并使用try..finally 块确保资源将被释放(在您的代码中frm 实例)。而且返回的mrCancel 看起来很奇怪。
  • @TLama,非常感谢!我使用了一个数据模块,它的工作原理!至于 txtName 中的 drop table,如何保护呢?最后我在块中添加 - “form2.Free”,我有一个错误(访问冲突......)。怎么了? mrCancel 我曾经关闭模式。
  • @TLama 您的评论是对这个问题的绝妙回应。评论中还有一件很有趣的事情:SQL Injection en.wikipedia.org/wiki/SQL_injection 。请将其发布为答案。

标签: delphi dbgrid


【解决方案1】:

使用你的模式,我会做这样的事情:

procedure TForm1.btnAddClick(Sender: TObject);
var
  frm : TForm2;
begin
  frm := TForm2.Create(form1);
  try
    if frm.ShowModal = mrOK then
    begin
      Grid.Datasource.Dataset.Refresh;
      // some databases require open/close to refresh
      // in this case Grid.Datasource.Dataset.close;
      //              Grid.Datasource.Dataset.Open;
    end;
  finally
    frm.Free;
  end
end;

procedure TForm2.btnAddClick(Sender: TObject);
var
  query : string;
begin
  query := 'Insert into Employees(Name) Values('''+txtName.Text+''');';
  DbOperations.InsertOrUpdate(query, ADOQuery1);
  ModalResult := mrOK;
  // let a cancel button on Form2 perform ModalResult = mrCancel  
  // to avoid unnecessary dataset refreshes..      
end;

【讨论】:

    【解决方案2】:

    解决从其他单元执行代码问题的更通用方法是简单地将事件添加到TForm2

     TForm2 = class(TForm)
     private
       FOnDataInserted : TNotifyEvent;
     public
       property OnDataInserted : TNotifyEvent read FOnDataInserted write FOnDataInserted;
     end;
    

    将此事件实现为:

    procedure TForm2.btnAddClick(Sender: TObject);
    var
      query : string;
    begin
      query := 'Insert into Employees(Name) Values('''+txtName.Text+''');';
      DbOperations.InsertOrUpdate(query, ADOQuery1);
      ModalResult := mrCancel;
      //And this here I'd refresh grid on form1
      If Assigned(FOnDatabaseInsert) then FOnDatabaseInsert(self);                
    end;
    

    现在,要为事件分配一个方法,在TForm1 中,声明一个合适的方法来处理它:

    procedure TForm1.Form2DataInserted(Sender: TObject);
    begin
      // do something, update grid, etc...
    end;
    

    在创建表单时:

    procedure TForm1.btnAddClick(Sender: TObject);
    var
      frm : TForm2;
    begin
      frm := TForm2.Create(form1);
      try
        frm.OnDataInserted := Form2DataInserted;
        frm.ShowModal;
      finally
        frm.Free;
      end;
    end;
    

    此模型允许您在代码中的任何位置执行任何类型的回调。这是依赖注入的一种形式,因为拥有组件提供了该方法 - TForm2 不包含对 TForm1 的任何引用,因此此方法保留了单元的隔离。

    正如 cmets 中的其他人所指出的,这可能不是您特定问题的理想解决方案,但它确实回答了直接问题,并提供了一种跨类和单元边界干净地调用代码的方法。

    【讨论】:

      【解决方案3】:

      简单的破解方法,不是我会做的

       (FOwner as TForm1).grid.refresh
      

      推荐的方法是在创建Form2后注册一个FreeNotification

      Forms.FreeNotification(Self).
      

      Form2 被销毁时,这将向Form1 发送一个通知方法。在 Form1 中添加一个事件

      protected
        procedure Notification(AComponent: TComponent; Operation: TOperation); override;
      

      实施中

      procedure TForm1.Notification(AComponent: TComponent; Operation: TOperation);
      begin
        inherited;
        if (AComponent is TForm) and (Operation = opRemove) then
        begin
          grid.Refresh;
        end;
      end; 
      

      注意我没用过,但是应该可以的。

      【讨论】:

      • 如果假设gridTDBGrid,那么refresh 方法只会强制重新绘制网格控件(这与要刷新的底层数据源无关)。而且通知方式很糟糕,因为每当发布表单时您都会刷新,例如即使用户只是取消对话框。
      猜你喜欢
      • 2012-05-25
      • 2015-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多