2017-10-31 13 views
8

मैं TEdit पर अपने स्वयं के चित्र को लागू करने की कोशिश कर रहा हूं, जब यह फोकस नहीं करता है (जब 0 संपादक पूरी तरह से अपना टेक्स्ट प्रदर्शित नहीं करता है तो 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) संदेश हैंडलर कुछ नहीं करता है।

अब मैं फार्म पर एक TButton और 2 TEdit नियंत्रण छोड़ दिया गया और प्रपत्र OnCreate कहा: संपादित करें नियंत्रण के अंदर कुछ भी आकर्षित करने के लिए नहीं

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    Edit2.FEllipsis := True; 
end; 

मैं Edit1 उम्मीद सामान्य रूप से आकर्षित करने के लिए, और Edit2

इसके बजाय संदेश हैंडलर को अंतहीन रूप से संसाधित किया गया था, Edit1 भी खींचा नहीं गया था, और पूरा एप्लिकेशन चोकिंग (25% CPU उपयोग के साथ!) था। मैंने 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 पर कॉल विंडो के क्लाइंट रेक्ट को मान्य करता है। यह उस जानकारी का महत्वपूर्ण हिस्सा है जिसमें आपकी कमी है।

अब, आपके कोड में, आपने inherited पर फोन नहीं किया था और इसलिए कुछ भी पेंट नहीं किया था, और BeginPaint/EndPaint पर कॉल नहीं किया था। क्योंकि आपने BeginPaint पर कॉल नहीं किया था, विंडो अमान्य बनी हुई है। और इसलिए WM_PAINT संदेशों की एक अंतहीन स्ट्रीम उत्पन्न होती है।

प्रासंगिक दस्तावेज here पाया जा सकता है:

BeginPaint समारोह स्वतः ही पूरे क्लाइंट क्षेत्र सत्यापित करता है।

+1

धन्यवाद! प्रलेखन ने यह स्पष्ट किया: * "सिस्टम वर्तमान अद्यतन क्षेत्र मान्य होने तक WM_PAINT संदेशों को उत्पन्न करना जारी रखता है" * – zig

+1

यह विंडोज संदेश पेंटिंग प्रक्रिया का सबसे अच्छा संक्षिप्त विवरण होना चाहिए जिसे मैंने अभी तक पढ़ा है। –

संबंधित मुद्दे