2017-02-24 25 views
0

新しいTEditコンポーネントを開発しようとしています。Delphiコンポーネントの開発 - コンポーネント内のイベントの伝播

TDBFilterEdit = class(TEdit) 

成分は、その編集フィールドに入力された文字列に基づいて関連付けられたデータセットをフィルタ処理することを意味します。

これは私のコンポーネントは次のようになります。今

type 
TDBFilterEdit = class(TEdit) 
    private 
    { Private-Deklarationen } 
    fFilter:String; 
    fDataSource:TDataSource; 
    fDataSet:TDataSet; 
    fText:string; 
    protected 
    { Protected-Deklarationen } 
    procedure SetFilter(value:String); 
    procedure SetDS(value:TDataSource); 
    procedure FilterRecords(DataSet:TDataSet; var Accept:Boolean); 
    procedure Change(Sender:TObject); 
    procedure SetText(value:String); 
    public 
    { Public-Deklarationen } 
    constructor Create(AOwner:TComponent); 
    published 
    { Published-Deklarationen } 
    property Text:String read fText write SetText; 
    property Filter:String read fFilter write SetFilter; 
    property DataSource:TDataSource read fDataSource write SetDS; 
    end; 

それは、コンポーネントの開発に来るとき、私はかなり初心者です。私の最初のアイデアは、データソースが自分のコンポーネントに割り当てられ、編集コンポーネントのテキストが変更されたときにトリガーするとすぐに、データセットのOnFilterRecordメソッドをオーバーライドすることでした。

procedure TDBFilterEdit.SetDS(value:TDataSource); 
var 
    myaccept:Boolean; 
begin 
    fDataSource:=value; 
    fDataSet:=fDataSource.DataSet; 
    if fDataSet=nil then Exit; 

    fDataSet.OnFilterRecord:=FilterRecords; 
    if Filter<>'' then fDataSet.OnFilterRecord(fDataSet,myaccept); 
end; 

私の問題は、コンポーネントのTextプロパティが更新されたことをコンポーネントに認識させる方法がわかりません。 OnChangeメソッドを次のコードでオーバーライドしようとしました。

procedure TDBFilterEdit.Change(Sender:TObject); 
begin 
    Filter:=Text; 
    inherited Change(); 
end; 

ただし、これまでのところ役に立たないです。

+0

をこれを行うには、変更内で呼び出されたメソッド(DoOnChangeと呼ばれることがあります)を記述し、必要なものを実行します。特別なイベントハンドラを呼び出すこともできます。 VCLのさまざまなDoOnxxxxメソッドを見て、すぐにそのアイデアを得るべきです。 – MartynA

答えて

4

私の問題は、コンポーネントに、そのTextプロパティが更新されたことを認識させる方法がわかりません。

TextプロパティはTControlから継承されます。プロパティ値が変更されると、TControlCM_TEXTCHANGED通知メッセージを自身に送信します。仮想WndProc()メソッドをオーバーライド

type 
    TDBFilterEdit = class(TEdit) 
    ... 
    procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED; 
    ... 
    published 
    ... 
    // DO NOT redeclare the Text property here! 
    // It is already published by TEdit... 
    end; 

procedure TDBFilterEdit.CMTextChanged(var Message: TMessage); 
begin 
    inherited; 
    // use new Text value as needed... 
    Filter := Text; 
end; 
  • messageハンドラを使用して

    1. :下位クラスのいずれかによって、そのメッセージを処理することができます。あなたのコンポーネントの残りの部分については

      type 
          TDBFilterEdit = class(TEdit) 
          ... 
          protected 
          ... 
          procedure WndProc(var Message: TMessage); override; 
          ... 
          end; 
      
      procedure TDBFilterEdit.WndProc(var Message: TMessage); 
      begin 
          inherited; 
          if Message.Msg = CM_TEXTCHANGED then 
          begin 
          // use new Text value as needed... 
          Filter := Text; 
          end; 
      end; 
      

    、それはより多くのようになります。

    type 
        TDBFilterEdit = class(TEdit) 
        private 
        { Private-Deklarationen } 
        fDataSource: TDataSource; 
        fDataSet: TDataSet; 
        fFilter: String; 
        procedure FilterRecords(DataSet: TDataSet; var Accept: Boolean); 
        procedure SetDataSource(Value: TDataSource); 
        procedure SetDataSet(Value: TDataSet); 
        procedure SetFilter(const Value: String); 
        procedure StateChanged(Sender: TObject); 
        procedure UpdateDataSetFilter; 
        protected 
        { Protected-Deklarationen } 
        procedure Notification(AComponent: TComponent; Operation: TOperation); override; 
        procedure WndProc(var Message: TMessage); override; 
        public 
        { Public-Deklarationen } 
        destructor Destroy; override; 
        published 
        { Published-Deklarationen } 
        property DataSource: TDataSource read fDataSource write SetDataSource; 
        property Filter: String read fFilter write SetFilter; 
        end; 
    
    ... 
    
    destructor TDBFilterEdit.Destroy; 
    begin 
        SetDataSource(nil); 
        inherited; 
    end; 
    
    procedure TDBFilterEdit.FilterRecords(DataSet: TDataSet; var Accept: Boolean); 
    begin 
        // ... 
    end; 
    
    procedure TDBFilterEdit.Notification(AComponent: TComponent; Operation: TOperation); 
    begin 
        inherited Notification(AComponent, Operation); 
        if Operation = opRemove then 
        begin 
        if AComponent = fDataSource then 
        begin 
         SetDataSet(nil); 
         fDataSource := nil; 
        end 
        else if AComponent = fDataSet then 
        begin 
         fDataSet := nil; 
        end; 
        end; 
    end; 
    
    procedure TDBFilterEdit.SetFilter(const Value: String); 
    begin 
        if fFilter <> Value then 
        begin 
        fFilter := Value; 
        UpdateDataSetFilter; 
        end; 
    end; 
    
    procedure TDBFilterEdit.SetDataSource(Value: TDataSource); 
    begin 
        if fDataSource <> Value then 
        begin 
        SetDataSet(nil); 
    
        if fDataSource <> nil then 
        begin 
         fDataSource.RemoveFreeNotification(Self); 
         fDataSource.OnStateChange := nil; 
        end; 
    
        fDataSource := Value;  
    
        if fDataSource <> nil then 
        begin 
         fDataSource.FreeNotification(Self); 
         fDataSource.OnStateChange := StateChanged; 
         SetDataSet(fDataSource.DataSet); 
        end; 
        end; 
    end; 
    
    procedure TDBFilterEdit.SetDataSet(Value: TDataSet); 
    begin 
        if fDataSet <> Value then 
        begin 
        if fDataSet <> nil then 
        begin 
         fDataSet.RemoveFreeNotification(Self); 
         fDataSet.OnFilterRecord := nil; 
        end; 
    
        fDataSet := Value; 
    
        if fDataSet <> nil then 
        begin 
         fDataSet.FreeNotification(Self); 
         fDataSet.OnFilterRecord := FilterRecords; 
         UpdateDataSetFilter; 
        end; 
        end; 
    end; 
    
    procedure TDBFilterEdit.StateChanged(Sender: TObject); 
    begin 
        if fDataSource.DataSet <> fDataSet then 
        SetDataSet(fDataSource.DataSet); 
    end; 
    
    procedure TDBFilterEdit.UpdateDataSetFilter; 
    begin 
        if fDataSet <> nil then 
        begin 
        fDataSet.Filter := fFilter; 
        fDataSet.Filtered := fFilter <> ''; 
        end; 
    end; 
    
    procedure TDBFilterEdit.WndProc(var Message: TMessage); 
    begin 
        inherited; 
        if Message.Msg = CM_TEXTCHANGED then 
        Filter := Text; 
    end; 
    

    UPDATE:申し訳ありませんが、私の悪いです。コード内でTextプロパティがプログラマブルに更新された場合にのみ、CM_TEXTCHANGEDメッセージが送信されます。 ユーザーがテキストを変更したときに検出するには、代わりにWin32のEN_CHANGE通知を処理する必要があります。

    1. messageハンドラを使用して仮想WndProc()メソッドをオーバーライド

      type 
          TDBFilterEdit = class(TEdit) 
          ... 
          procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED; 
          procedure CNCommand(var Message: TWMCommand); message CN_COMMAND; 
          ... 
          published 
          ... 
          // DO NOT redeclare the Text property here! 
          // It is already published by TEdit... 
          end; 
      
      procedure TDBFilterEdit.CMTextChanged(var Message: TMessage); 
      begin 
          inherited; 
          // use new Text value as needed... 
          Filter := Text; 
      end; 
      
      procedure TDBFilterEdit.CNCommand(var Message: TWMCommand); 
      begin 
          inherited; 
          if Message.NotifyCode = EN_CHANGE then 
          begin 
          // use new Text value as needed... 
          Filter := Text; 
          end; 
      end; 
      
    2. 。実際に

      type 
          TDBFilterEdit = class(TEdit) 
          ... 
          protected 
          ... 
          procedure WndProc(var Message: TMessage); override; 
          ... 
          end; 
      
      procedure TDBFilterEdit.WndProc(var Message: TMessage); 
      begin 
          inherited; 
          case Message.Msg of 
          CM_TEXTCHANGED: begin 
           // use new Text value as needed... 
           Filter := Text; 
          end; 
          CN_COMMAND: begin 
           if TWMCommand(Message).NotifyCode = EN_CHANGE then 
           begin 
           // use new Text value as needed... 
           Filter := Text; 
           end; 
          end; 
          end; 
      end; 
      

    TCustomEditはすでにあなたのためEN_CHANGEを処理し、あなたがオーバーライドすることができ、仮想Change()方法(そのOnChangeイベントを発生させる)、呼び出します。通常の方法

    type 
         TDBFilterEdit = class(TEdit) 
         ... 
         protected 
         ... 
         procedure Change; override; 
         ... 
         end; 
    
        procedure TDBFilterEdit.Change; 
        begin 
         inherited; 
         // use new Text value as needed... 
         Filter := Text; 
        end; 
    
  • +0

    あなたの答えをありがとう、それは私の目標にさらに手伝ってくれました。 方法1を選択し、CMTextChanged-message-Handlerを作成しましたが、 は起動しません。 私はCM_MOUSEENTERメッセージハンドラを試しましたが、DIDは起動しますが、Textプロパティは空のままです。 Notification、StateChange、WndProcなどの他の手順を実装または上書きする必要がありますか? また、データソースの割り当ては機能しますが、いくつかの奇妙な理由で、データソースのDataSetはゼロに残ります –

    +0

    私が探している正しいメッセージハンドラがCN_COMMANDであることがわかりました。編集フィールドに最初の文字を入力します。 どのようにすべてのボタンを押してこれを呼び出すか考えていますか? –

    +0

    私はそれを理解しました。データセットは、filtered:= falseからfiltered:= trueに切り替えるときにのみ、OnFilterRecordを実行します。 フィルタリングされたプロパティをどこにもリセットしていないので、編集フィールドに最初の文字を入力した後は常に値がtrueでした。 コンポーネントはほとんど意図したとおりに動作しますが、残っているのは、データソースを割り当てるときの "nil-Dataset"の不思議な振る舞いを研究していることです(データソースの代わりに直接データセットを使用します) FilterRecords-メソッド。 –

    関連する問題