表单控件(Edit,ComboBox,Memo等)查询是否已修改?

时间:2019-02-15 12:16:35

标签: delphi

当用户在Programm中添加或更改某些内容时,我在FormQuery上检查是否进行了某些修改并且未完成保存,并且警告用户如果退出该用户,所有数据将丢失。

问题是我一次检查一个组件。编辑已修改,但DateTimePicker则没有。

我的问题是:如果可能,如何用一个命令检查表单上的内容是否有所更改?有控制权吗?

更新

我正在考虑是否存在通用的东西,像这样的东西,但是对于每个可由用户以任何方式更改的控制器。

将4个TEdit拖放到窗体上,并放置一个TLabel。

procedure TForm1.SomethingChanged(Sender: TObject);
begin
  Label1.Caption:='SOMETHING CHANGED!';
end;

在TForm.Create上,我这样做:

procedure TForm1.FormCreate(Sender: TObject);
var i : integer;
    Child : TComponent;
begin
  for i := 0 to ComponentCount-1 do
  begin
    Child := Components[i];

    if Child is TEdit then
      TEdit(Child).OnChange:=SomethingChanged;

    if Child is TDateTimePicker then
      TDateTimePicker(Child).OnChange:=SomethingChanged;

    if Child is TComboBox then
      TComboBox(Child).OnChange:=SomethingChanged;
  end;
end;

我可以为所有控件(例如Editors,DateTimePickers,ComboBoxes等)创建此控件,但我当时想也许有一些很酷的“秘密”更聪明的方法可以做到这一点。

谢谢

更新2

现在我还有另一个问题,如果可能的话,不知道。假设其中一个TEdit的onChange事件定义如下:

procedure TForm1.Edit1Change(Sender: TObject);
begin
  Label2.Caption:='THIS WAS EDIT1CHANGE';
end;

当应用程序启动时,这将重置为我的自定义onChange事件,并且永远不会运行该事件。

是否可以通过某种方式链接onChange事件?

就像我有一个地方,我只检查是否发生了某些变化……但是我允许TEdit执行它的“正常” onChange事件。

谢谢

2 个答案:

答案 0 :(得分:2)

我认为关键在于这些组件主要是TWinControl的后代,所以为什么不挂接到它们的OnChange消息CM_CHANGED,这样就不会像您所说的那样发生OnChange事件链接问题(我希望涉及事件时,Delphi带有C#+ =运算符之类的东西。

您将需要以下课程来实现

1。 TListener

TListener = class
    private
    FOnChangeHappend: TNotifyEvent;
    FWinControl: TWinControl;
    FMsgToListen: Cardinal;
    FOldWndProc: System.Classes.TWndMethod;
    procedure FWindowProc(var Message: TMessage);
    public
    constructor Create(aWinControl: TWinControl; aMsg: Cardinal);
    Destructor Destroy;
    property OnChangeHappend: TNotifyEvent read FOnChangeHappend write FOnChangeHappend;
  end;
{ TListener }

constructor TListener.Create(aWinControl: TWinControl; aMsg: Cardinal);
begin
    FMsgToListen := aMsg;
    FWinControl := aWinControl;
    FOldWndProc := aWinControl.WindowProc;
    aWinControl.WindowProc := FWindowProc;    
end;

destructor TListener.Destroy;
begin
  if Assigned(FOldWndProc) then
    FWinControl.WindowProc := FOldWndProc;
  inherited Destroy;
end;

procedure TListener.FWindowProc(var Message: TMessage);
begin
    if ((Message.Msg = FMsgToListen) and (Assigned(FOnChangeHappend))) then
    begin
      FOnChangeHappend(FWinControl);
    end;
    FOldWndProc(Message);
end;

2。 TListenerList

TListenerList = class
    private
    FListners: TObjectList<TListener>;
    FOnChangeHappend: TNotifyEvent;
    public
    constructor Create;
    Destructor Destroy;
    procedure ListenTo(aWinControl: TWinControl; aMsg: Cardinal);
    property OnChangeHappend: TNotifyEvent read FOnChangeHappend write FOnChangeHappend;
  end;
{ TListenerList }

constructor TListenerList.Create;
begin
  FListners := TObjectList<TListener>.Create;
  FListners.OwnsObjects := True;
end;

destructor TListenerList.Destroy;
begin
  FListners.Free;
end;

procedure TListenerList.ListenTo(aWinControl: TWinControl; aMsg: Cardinal);
var
  aListener: TListener;
begin
  aListener := TListener.Create(aWinControl, aMsg);
  aListener.OnChangeHappend := FOnChangeHappend;
  Flistners.Add(aListener);
end;

您可以在表单的OnCreate事件中使用它

procedure TForm8.FormCreate(Sender: TObject);
begin
  FListenerList := TListenerList.Create();
  FListenerList.OnChangeHappend := TextChanged;

  FListenerList.ListenTo(DBEdit1, CM_CHANGED);
  FListenerList.ListenTo(DBMemo1, CM_CHANGED);
  FListenerList.ListenTo(DBComboBox1, CM_CHANGED);
  FListenerList.ListenTo(DBCheckBox1, CM_CHANGED);
  FListenerList.ListenTo(DBRichEdit1, CM_CHANGED);
  FListenerList.ListenTo(Memo1, CM_CHANGED);
  FListenerList.ListenTo(Edit1, CM_CHANGED);
  FListenerList.ListenTo(ComboBox1, CM_CHANGED);
  FListenerList.ListenTo(DateTimePicker1, CM_CHANGED);
  FListenerList.ListenTo(CheckBox1, CM_CHANGED);
end;

procedure TForm8.TextChanged(Sender: TObject);
begin
  memo2.Lines.Add(TWinControl(Sender).Name + 'Changed');
end;

,但此消息有限制。例如,如果编辑控件的文本为“ Hello”,而您想删除它(按返回键),则将触发Listener事件五次(每个字母一个),因此在记录时应使用CM_ENTER和CM_EXIT消息输入每个TWinControl的值时(具有焦点),然后将其与退出时的值进行比较(失去焦点)。

此方法适用于任何TWinControl后代(用户可以与之交互的几乎所有控件)

答案 1 :(得分:1)

如果使用dbedit,dbcombobax ..您可以进行控制。

因为
您必须将它们链接到表或查询。
您必须将数据源用于链接。

if table1.state=dsedit then 
begin
end;

如果使用编辑,则定义一个变量。

在所有字段的onchange事件中将值分配给变量。然后检查此变量。

procedure Tform1.editChange (Sender: TObject);
begin
  variable_change:= 'YES';
end;

if variable_change = 'YES' then
  begin
  end;