2017-10-31 10 views
8

TEdit 컨트롤에 포커스가 없을 때 내 자신의 그림을 구현하려고합니다 (편집기가 텍스트를 완전히 표시하지 않을 때 TEdit에 줄임표가 표시됨). 그래서이 코드 א 에드 스타 :TEdit 및 WM_PAINT 메시지 처리기 이상한 동작

type 
    TEdit = class(StdCtrls.TEdit) 
    private 
    FEllipsis: Boolean; 
    FCanvas: TCanvas; 
    procedure WMPaint(var Message: TWMPaint); message WM_PAINT; 
    public 
    constructor Create(AOwner: TComponent); override; 
    destructor Destroy; override; 
    end; 

constructor TEdit.Create(AOwner: TComponent); 
begin 
    inherited Create(AOwner); 
    FEllipsis := False; 
    FCanvas := TControlCanvas.Create; 
    TControlCanvas(FCanvas).Control := Self; 
end; 

destructor TEdit.Destroy; 
begin 
    FCanvas.Free; 
    inherited; 
end; 

procedure TEdit.WMPaint(var Message: TWMPaint); 
begin 
    if FEllipsis and (not Focused) then 
    begin 
    // Message.Result := 0; 
    // TODO... 
    end 
    else 
    inherited; 
end; 

공지 사항을 FEllipsis and (not Focused) 메시지 처리기는 아무것도하지 않습니다 때.

는 이제 폼에 컨트롤을 떨어 및 형태 OnCreate 추가 : 편집 컨트롤 내부에 아무것도 그려하지
procedure TForm1.FormCreate(Sender: TObject); 
begin 
    Edit2.FEllipsis := True; 
end; 

내가 일반적으로 그릴 Edit1을 예상하고 Edit2을.

대신 메시지 처리기가 끝없이 처리되었으므로 도 그려지지 않았으며 전체 응용 프로그램이 숨 막히게되었습니다 (CPU 사용량 25 %)! 나는 또한 같은 효과를 Message.Result := 0 반환 시도했습니다.

"이상한"부분에 대해 : BeginPaint으로 캔버스 핸들을 얻으면 모든 것이 예상대로 작동합니다.

procedure TEdit.WMPaint(var Message: TWMPaint); 
var 
    PS: TPaintStruct; 
begin 
    if FEllipsis and (not Focused) then 
    begin  
    if Message.DC = 0 then 
     FCanvas.Handle := BeginPaint(Handle, PS) 
    else 
     FCanvas.Handle := Message.DC; 
    try 
     // paint on FCanvas... 
    finally 
     FCanvas.Handle := 0; 
     if Message.DC = 0 then EndPaint(Handle, PS); 
    end; 
    end 
    else 
    inherited; 
end; 

알림 inherited도 알려지지 않았습니다.

이 동작을 설명하는 방법? 감사.

답변

13

창이 무효화되면, 다음 페인트 사이클에서 자신을 유효하게 만들도록 요청받습니다. 일반적으로 대기열이 비어 있다는 것을 발견하면 GetMessage이 주 스레드 메시지 루프에서 발생합니다. 그 시점에서 WM_PAINT 메시지가 합성되어 창으로 전달됩니다.

창이 이러한 메시지를 받으면 자체 작업을 그립니다. 일반적으로 BeginPaint을 호출 한 다음 EndPaint을 호출하면됩니다. BeginPaint에 대한 호출은 윈도우의 클라이언트 rect를 확인합니다. 이것은 당신이 부족한 중요한 정보입니다.

코드에서 inherited을 호출하지 않았으므로 아무 것도 페인트하지 않았으며 BeginPaint/EndPaint을 호출하지 않았습니다. BeginPaint에 전화하지 않았으므로 창은 유효하지 않습니다. 그리고 무한의 WM_PAINT 스트림이 생성됩니다.

관련 문서

here를 찾을 수 있습니다

BeginPaint 함수 기능이 자동으로 전체 클라이언트 영역의 유효성을 검사합니다.

+1

고마워요! 설명서는 다음 사항을 분명히했습니다. * "현재 업데이트 영역이 유효화 될 때까지 WM_PAINT 메시지가 계속 생성됩니다."* – zig

+1

이것은 아직 읽지 않은 Windows 메시지 페인팅 프로세스에 대한 간단한 설명입니다. –