2017-02-24 1 views
0

새로운 TEdit 구성 요소를 개발하려고합니다.델파이 구성 요소 개발 - 구성 요소 내에서 이벤트 전파

TDBFilterEdit = class(TEdit) 

구성 요소는 Edit-Field에 입력 된 문자열을 기반으로 연결된 DataSet을 필터링합니다.

이처럼 내 구성 요소 모습입니다 : 그것은 구성 요소 개발에 올 때

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; 

지금, 나는 꽤 초보자입니다. 내 첫 번째 아이디어는 DataSource가 내 구성 요소에 지정되면 즉시 데이터 집합의 OnFilterRecord 메서드를 재정의하고 내 Edit 구성 요소의 텍스트가 변경 될 때마다 트리거합니다.

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-Method를 재정의하려고 시도했습니다.

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

그러나 지금까지는 아무 소용이 없습니다.

+0

일반적인 방법 이렇게하려면 변경 내에서 호출되는 메서드 (DoOnChange라고도 함)를 작성하고 제공하려는 특수 이벤트 처리기를 호출하는 등 원하는 작업을 수행해야합니다. VCL에서 다양한 DoOnxxxx 메소드를 살펴보고 곧 아이디어를 얻으십시오. – MartynA

답변

4

내 문제는 구성 요소가 Text 속성이 업데이트되었음을 ​​알리는 방법을 알지 못합니다.

Text 속성은 TControl에서 상속됩니다. 속성 값이 변경되면 TControlCM_TEXTCHANGED 알림 메시지를 자체에 보냅니다. 하위 클래스 중 하나에 의해 그 메시지를 처리 ​​할 수 ​​

  1. message 핸들러를 사용 :

    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; 
    
  2. WndProc() 가상 메소드를 재정의. 구성 요소의 나머지 부분에 관해서는

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 처리하고 재정의 할 수있는, (그 OnChange 이벤트가 발생하는) 가상 Change() 메소드를 호출 :의

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-Message Handler를 시도했지만 DID가 발생했지만 Text 속성이 비어 있습니다. Notification, StateChange 및 WndProc와 같은 다른 절차를 구현하거나 재정의해야합니까? 또한 데이터 소스 할당이 작동하지만 일부 이상한 이유로 내 데이터 소스의 DataSet이 무효로 유지됩니다. –

+0

정확한 메시지 처리기가 CN_COMMAND 인 것을 알았습니다. 편집 필드에 첫 글자를 입력합니다. 모든 버튼을 누를 때마다 어떻게 호출 할 수 있습니까? –

+0

데이터 집합은 filtered : = false에서 filtered : = true로 전환 할 때만 OnFilterRecord를 실행합니다. 필터링 된 속성을 어디에도 다시 설정하지 않았으므로 편집 필드에 첫 번째 문자를 입력 한 후에 값이 항상 true였습니다. 이제 구성 요소가 거의 의도 한대로 동작합니다. 데이터 소스를 할당 할 때 "nil-Dataset"의 신비한 동작을 연구하는 것만 남았습니다 (아마도 데이터 소스 대신 데이터 세트를 직접 사용하게 될 것입니다). FilterRecords- 방법입니다. –

관련 문제