讲述如何开发一个控件,很有价值(七)
来源:岁月联盟
编辑:exp
时间:2009-05-20
SUCCESS - (Nearly...)
I think youll agree we are pretty close. There is just a little bit of flicker. This flicker is the SelStart jumping the Cursor position around the text. We need to hide this. This "Cursor" is also known as a Caret. Looking throught Win32.Hlp again we find the lovely, and appropriately named, HideCaret() function.
Lets try this then: everytime we change the value of MyRe.SelStart lets call HideCaret(MyRe.Handle) immediately before.
Ill be kind - that doesnt work. I tried 2 x HideCaret(MyRe.Handle), and it still didnt work. Neither did three,four or 25x. So close - but yet - so far. I think its time for another Delphi Rule:
DELPHI RULE #5 - If you bother to get your way through the atrocious index of the Win32.HLP file to find what you are looking for - make sure you really read what you found properly!
The key was the last paragraph in the description of not HideCaret but ShowCaret (which I had also read as I thought we were going to need it, especially to reverse my 25x HideCaret()). You also need another Delphi Rule to understand it:
The caret is a shared resource; there is only one caret in the system. A window should show a caret only when the window has the keyboard focus or is active. DELPHI RULE #6 - Everything (basically) is a Window You see the RichEdit is a windows control and is also.. in a weird sense.. a window. It has a Handle, which is why HideCaret would accept it. So re-reading the last line again we get: The caret is a shared resource; there is only one caret in the system. A [RichEdit] should show a caret only when the [RichEdit] has the keyboard focus or is active. So - in the end - were back to were we started - we have to disable the RichEdit to stop the final bit of flickering. This also (co-incidentially) means that EM_HIDESELECTION is not needed anymore (if HideSelection is set properly during Design time). So in the end everyone gets 10/10 for marks! ASH Version 0.9b procedure TForm1.RichEdit1Change(Sender: TObject); var SaveOnChangeIn: TNotifyEvent; WasSelStart,WasRow,Row,BeginSelStart,EndSelStart: Integer; MyRe : TRichEdit; MyPBuff: array[0..255] of char; MyTokenStr:string; MyTokenState:TTokenState; MyRun:PChar; MySelStart: Integer;
begin MyRe := TRichEdit(Sender); SaveOnChangeIn := MyRe.OnChange; MyRe.OnChange := nil; MyRe.Enabled := False; WasSelStart := MyRE.SelStart; WasRow := MyRE.Perform(EM_LINEFROMCHAR, MyRE.SelStart, 0); Row := WasRow; BeginSelStart := MyRe.Perform(EM_LINEINDEX, Row, 0); EndSelStart := BeginSelStart + Length(MyRE.Lines.Strings[Row]); StrPCopy(MyPBuff,MyRE.Lines.Strings[Row]); MYPBuff[Length(MyRE.Lines.Strings[Row])] := #0; MySelStart := BeginSelStart; MyRun := MyPBuff; while(MyRun^ <> #0) do begin MyRun := PasCon.GetToken(MyRun,MyTokenState,MyTokenStr); MyRE.SelStart := MySelStart; MyRE.SelLength := Length(MyTokenStr); If MyRE.SelAttributes.Name <> PasCon.FParseFont[MyTokenState].Name then MyRE.SelAttributes.Name := PasCon.FParseFont[MyTokenState].Name; If MyRE.SelAttributes.Color <> PasCon.FParseFont[MyTokenState].Color then MyRE.SelAttributes.Color := PasCon.FParseFont[MyTokenState].Color; if MyRE.SelAttributes.Style <> PasCon.FParseFont[MyTokenState].Style then MyRE.SelAttributes.Style := PasCon.FParseFont[MyTokenState].Style; MySelStart := MySelStart + Length(MyTokenStr);
end; MyRE.SelStart := WasSelStart; MyRE.SelLength := 0; MyRe.OnChange := SaveOnChangeIn; MyRe.Enabled := True; MyRe.SetFocus;
end; Towards - ASH Version 1.0b Couple of problems with the last version if you try it out for size: - Its slightly inefficient in that everytime SelAttributes is changed it forces a repaint of the same token in the control. We should instead use some variable (e.g var DoFormat:Boolean) to decided if we need to reformat, and then check the value of DoFormat at the end of this chec
|
|
|