一行のコードはTForm色の前世の生を設定します.
9156 ワード
万が一からの投稿:http://www.cnblogs.com/del/archive/2008/04/27/1173658.html確かに行コード設定TFormコントロールの色を作りました.しかし、実際の状況は、VCLフレームがこの過程で大量の作業を行い、複数のメッセージの送信と応答を経て、目的を達成しました.大体の順序は以下の通りです.
TCustom Form.WMEraseBkgnd(var Message:TWMEraseBkgnd)//通常の状況とアイコンの状況を区別するTWinControl.WMEraseBkgnd(var Message:TWMEraseBkgnd);背景色を描く(古い背景を消すのに相当)TCustom Form.WMPaint;通常の状況とアイコンの状況を区別するTWinControl.WMPaint;ダブルバッファとセルフ絵を判断するには、ごく少数のWindowsが持つコントロールのパッケージ(例えば、TEdit、TButton)以外は、PaintHandlerがTWinControl.PaintHandler(var Message:TWMPaint)を実行します.まず、現在のwinコントロールを描画します.例えば、Form 1(おそらくトリミングした後の残りの部分)を描画して、そのすべての図形のサブコントロールのprocedure TCustom Form.PaintWindow(DC:HDC)//WM_を使うPAINTメッセージは、DCハンドルでForm 1フォームのprocedure TCustom.Paintを描きます.プログラマイベントを呼び出したり、デザイン時のグリッドを表示したりします.
------------------------------------------
Form 1の初期色はどこに設定されていますか?回答はコードに設定されていませんが、dfmにclBtnFace色が設定されています.手動でclRedに変更すれば、すぐに効果が見られます.これは空白のフォームのdfm内容で、全部で14項目です.
また、なぜTCustom Formでソースコードを直接変更したのか、最終的に分かりましたが、効果はなかなか得られませんでした.
------------------------------------------
Form 1.Coolorについて、Brush.Coolor、Canvas.Brush.Coolorの3つの色の値の間の関係分析:この2つを使えば、Color:=clRed;Brush.Coolor:=clBlue;TCustom Form.reateに書いてありますが、どちらを後ろに書いても後の文の色に合わせて設定されます.しかし、その過程は違っています.1.もしColor:=clRed;後に書いてください.クラスの属性を呼び出したのと、後の一連の変化に相当します.TWinControl.C MColorChendを実行すると、FBrush.Coolor=Flarを実行します.FBRUsh.Coolorの値をカバーするに相当します.前の文の効果は無効になります.2.Brush.Coolor:=clBlue;後に書いて、前の文の効果を実行した後に、Brush.Coolorの値を簡単に上書きしました.前の文の効果は自然に効果がありません.まとめ:この二つの言葉は同じ効果がありますが、実行過程は大きく違っています.Brush.Coolorを使う:=clBlue;これはDelphiの言語レベルだけで値を変えて、背景を更新する時にFillRectに直接使用させます.Colorを使用する場合:=clRed;実は2歩に分けて、第1歩は全体のForm 1の取引先の区を失効させるので、第2歩はDelphi言語のレベルがBrushの値を変えるのです.この上の二歩は全部WM_です.ERASEBKGNDメッセージとWM_PAINTメッセージは来る前に準備しています.そうすると、メッセージが更新されるとすぐに更新効果があります.
以上の分析を通して、私は突然問題に気づきました.Brush.Coolorを直接実行すれば、ブラシの色を変えただけで、顧客エリアを失効させませんでした.効果がありますか?試してみました.procedure TForm 1.Button 2 lick(Sender:TObject)BeginBrush.Coolor:=clGreen;end;ボタンを押すと、フォーム1はやはり色を変える効果がありません.この説明はブラシの色が変えられましたが、結局一つのステップが足りなくなりました.取引先エリアは無効になりませんので、やはり効果がありません.次の顧客エリアが失効するまで、効果が発揮されるので、ウィンドウを最小化して、再度最大化を回復します.そうすると、Form 1クライアントエリアは緑色になります.そしてこれからもずっと緑を保っています.もっと面白いのは、別のウィンドウ(例えばメモ帳)でForm 1の一部の顧客エリアをブロックしてから移動すると、この部分の顧客エリアの色は緑色で、他の部分はまだ赤色です.
constructor TCustom Form.reatにBrush.Coolorを書きます.すぐに有効になります.Form 1は一度も表示されていないので、初めて表示される時には、自動的に背景メッセージを消去します.ブラシの色は先ほど設定された色です.FillRect APIに直接使用されますので、すぐに効果があります.ですから、これは特殊な状況です.普通の状況ではいけません.このように変更できます.procedure TForm 1.Button 3 Click(Sender:TObject)beginnInvalidate;Brush.Coolor:=clGreen;end;このようにVCLフレームの実行過程とは意味があります.もちろん効果があります.更にこのように変えます.procedure TForm 1.Button 3 Click(Sender:TObject);BeginBrush.Coolor:=clGreen;Invalidate;end;同じ効果がありますが、実はこのように書くのがもっと合理的だと思います.準備万端です.またメッセージを送って対応します.もちろん大丈夫です.
TCustom Form.ccoolorChend関数にはありますが、if Flavas<>nil then Fravas.Brush.Color;しかし、これはキャンバスの絵を専門に使う時に使います.このときVCLはFillRect APIが描いた効果を使っていますので、この言葉を遮断しても大丈夫です.
最後にコードでこの三つの色の関係をまとめます.
もう一つの問題は、この色がどのwindapiを使っているかということです.FillRectを検索することによって分かります.
まとめ:クラスの属性を変更するとすぐに有効になります.クラスの属性に対応するSet関数を呼び出して、メッセージを送って本当にウィンドウに表示します.WM_ならメッセージは直接問題を解決することができます.フォームのタイトルを設定するなど、十分ではない場合もあります.CMを使う必要があります.メッセージはさらに、フォームの色を変更するなどの処理に役立ちます.
procedure TForm1.Button1Click(Sender: TObject);
begin
Self.Color := clRed;
end;
procedure TControl.SetColor(Value: TColor);
begin
if FColor <> Value then
begin
FColor := Value;
FParentColor := False;
Perform(CM_COLORCHANGED, 0, 0); // , , ,
end;
end;
procedure TCustomForm.CMColorChanged(var Message: TMessage);
begin
inherited;
if FCanvas <> nil then FCanvas.Brush.Color := Color; // Canvas.Brush.Color , , ,VCL FillRect API, Canvas,
end;
procedure TWinControl.CMColorChanged(var Message: TMessage);
begin
inherited; // , , 。 , 。
FBrush.Color := FColor; // , , Brush
NotifyControls(CM_PARENTCOLORCHANGED); // , , ,
end;
procedure TControl.CMColorChanged(var Message: TMessage);
begin
Invalidate; // , 。 TWinControl.Invalidate;
end;
procedure TWinControl.Invalidate;
begin
// , WParam 0, API , 。
Perform(CM_INVALIDATE, 0, 0); // , , CM , 。 , , 。
end;
procedure TWinControl.CMInvalidate(var Message: TMessage);
var
I: Integer;
begin
if HandleAllocated then
begin
if Parent <> nil then
Parent.Perform(CM_INVALIDATE, 1, 0); // , , ( )。Form1 Parent Application, 。
if Message.WParam = 0 then
begin
// API, NULL , ; TRUE 。
InvalidateRect(FHandle, nil, not (csOpaque in ControlStyle)); // , Form1 ,
{ Invalidate child windows which use the parentbackground when themed }
if ThemeServices.ThemesEnabled then
for I := 0 to ControlCount - 1 do
if csParentBackground in Controls[I].ControlStyle then // important
Controls[I].Invalidate;
end;
end;
end;
以上の過程はForm 1の画板を失効させました(結局、Form 1.Fravas.Brushを通じて作用します.クラスの属性Colorは表象だけです.)、続いてもう一つのForm 1を描く過程があります.TForm 1はTFormから継承され、TFormはTWinControlから継承され、TCustomControlではなく、WM_に応答します.PAINTメッセージはWMPaint関数をカバーしていますので、WindowsはWM(u)をPAINTは直接Form 1に送ります.呼び出し順序は以下の通りです.TCustom Form.WMEraseBkgnd(var Message:TWMEraseBkgnd)//通常の状況とアイコンの状況を区別するTWinControl.WMEraseBkgnd(var Message:TWMEraseBkgnd);背景色を描く(古い背景を消すのに相当)TCustom Form.WMPaint;通常の状況とアイコンの状況を区別するTWinControl.WMPaint;ダブルバッファとセルフ絵を判断するには、ごく少数のWindowsが持つコントロールのパッケージ(例えば、TEdit、TButton)以外は、PaintHandlerがTWinControl.PaintHandler(var Message:TWMPaint)を実行します.まず、現在のwinコントロールを描画します.例えば、Form 1(おそらくトリミングした後の残りの部分)を描画して、そのすべての図形のサブコントロールのprocedure TCustom Form.PaintWindow(DC:HDC)//WM_を使うPAINTメッセージは、DCハンドルでForm 1フォームのprocedure TCustom.Paintを描きます.プログラマイベントを呼び出したり、デザイン時のグリッドを表示したりします.
------------------------------------------
Form 1の初期色はどこに設定されていますか?回答はコードに設定されていませんが、dfmにclBtnFace色が設定されています.手動でclRedに変更すれば、すぐに効果が見られます.これは空白のフォームのdfm内容で、全部で14項目です.
object Form1: TForm1
Left = 0
Top = 0
Height = 282
Width = 418
Caption = 'Form1'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
end
------------------------------------------また、なぜTCustom Formでソースコードを直接変更したのか、最終的に分かりましたが、効果はなかなか得られませんでした.
constructor TCustomForm.CreateNew(AOwner: TComponent; Dummy: Integer);
begin
Color := clRed; // ?
Brush.Color := clRed;
FCanvas.Brush.Color := clRed;
end;
TFormの作成順序は以下の通りです.begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
procedure TApplication.CreateForm(InstanceClass: TComponentClass; var Reference);
var
Instance: TComponent;
begin
Instance := TComponent(InstanceClass.NewInstance); // , 。
TComponent(Reference) := Instance;
try
Instance.Create(Self); // TForm.Create;
except
TComponent(Reference) := nil;
raise;
end;
if (FMainForm = nil) and (Instance is TForm) then
begin
TForm(Instance).HandleNeeded;
FMainForm := TForm(Instance);
end;
end;
TForm.reateは先にTForm.reat Newを呼び出すことができます.後にInitInhered Componentを呼び出してdfmファイルを読み込むと、記憶ワードdfmファイルの色が私の手動で指定したclRed色を覆っています.これはずっと有効になりません.だからTCustom Form.reate関数の中のInitInheited Component文の後で書くべきです:Color:=clBlue;Brush.Coolor:=clBlue;すぐ有効になります.でも、書いたら:Canvas.Brush.Coolor:=clBlue;これは、Canvasがこの過程で使われていないため、TCustom Form.ccoolorChend関数でクラスの属性Colorの値によってカバーされているため、有効になりません.------------------------------------------
Form 1.Coolorについて、Brush.Coolor、Canvas.Brush.Coolorの3つの色の値の間の関係分析:この2つを使えば、Color:=clRed;Brush.Coolor:=clBlue;TCustom Form.reateに書いてありますが、どちらを後ろに書いても後の文の色に合わせて設定されます.しかし、その過程は違っています.1.もしColor:=clRed;後に書いてください.クラスの属性を呼び出したのと、後の一連の変化に相当します.TWinControl.C MColorChendを実行すると、FBrush.Coolor=Flarを実行します.FBRUsh.Coolorの値をカバーするに相当します.前の文の効果は無効になります.2.Brush.Coolor:=clBlue;後に書いて、前の文の効果を実行した後に、Brush.Coolorの値を簡単に上書きしました.前の文の効果は自然に効果がありません.まとめ:この二つの言葉は同じ効果がありますが、実行過程は大きく違っています.Brush.Coolorを使う:=clBlue;これはDelphiの言語レベルだけで値を変えて、背景を更新する時にFillRectに直接使用させます.Colorを使用する場合:=clRed;実は2歩に分けて、第1歩は全体のForm 1の取引先の区を失効させるので、第2歩はDelphi言語のレベルがBrushの値を変えるのです.この上の二歩は全部WM_です.ERASEBKGNDメッセージとWM_PAINTメッセージは来る前に準備しています.そうすると、メッセージが更新されるとすぐに更新効果があります.
以上の分析を通して、私は突然問題に気づきました.Brush.Coolorを直接実行すれば、ブラシの色を変えただけで、顧客エリアを失効させませんでした.効果がありますか?試してみました.procedure TForm 1.Button 2 lick(Sender:TObject)BeginBrush.Coolor:=clGreen;end;ボタンを押すと、フォーム1はやはり色を変える効果がありません.この説明はブラシの色が変えられましたが、結局一つのステップが足りなくなりました.取引先エリアは無効になりませんので、やはり効果がありません.次の顧客エリアが失効するまで、効果が発揮されるので、ウィンドウを最小化して、再度最大化を回復します.そうすると、Form 1クライアントエリアは緑色になります.そしてこれからもずっと緑を保っています.もっと面白いのは、別のウィンドウ(例えばメモ帳)でForm 1の一部の顧客エリアをブロックしてから移動すると、この部分の顧客エリアの色は緑色で、他の部分はまだ赤色です.
constructor TCustom Form.reatにBrush.Coolorを書きます.すぐに有効になります.Form 1は一度も表示されていないので、初めて表示される時には、自動的に背景メッセージを消去します.ブラシの色は先ほど設定された色です.FillRect APIに直接使用されますので、すぐに効果があります.ですから、これは特殊な状況です.普通の状況ではいけません.このように変更できます.procedure TForm 1.Button 3 Click(Sender:TObject)beginnInvalidate;Brush.Coolor:=clGreen;end;このようにVCLフレームの実行過程とは意味があります.もちろん効果があります.更にこのように変えます.procedure TForm 1.Button 3 Click(Sender:TObject);BeginBrush.Coolor:=clGreen;Invalidate;end;同じ効果がありますが、実はこのように書くのがもっと合理的だと思います.準備万端です.またメッセージを送って対応します.もちろん大丈夫です.
TCustom Form.ccoolorChend関数にはありますが、if Flavas<>nil then Fravas.Brush.Color;しかし、これはキャンバスの絵を専門に使う時に使います.このときVCLはFillRect APIが描いた効果を使っていますので、この言葉を遮断しても大丈夫です.
最後にコードでこの三つの色の関係をまとめます.
procedure TForm1.Button2Click(Sender: TObject);
begin
Brush.Color := clGreen;
if (Color=clGreen) then
ShowMessage('yes'); //
if (Canvas.Brush.Color=clGreen) then
ShowMessage('yes'); //
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
Color := clGreen;
if (Brush.Color=clGreen) then
ShowMessage('yes'); //
if (Canvas.Brush.Color=clGreen) then
ShowMessage('yes'); //
end;
procedure TForm1.Button4Click(Sender: TObject);
begin
Canvas.Brush.Color := clGreen;
if (Brush.Color=clGreen) then
ShowMessage('yes'); //
if (Color=clGreen) then
ShowMessage('yes'); //
end;
------------------------------------------もう一つの問題は、この色がどのwindapiを使っているかということです.FillRectを検索することによって分かります.
procedure TWinControl.WMEraseBkgnd(var Message: TWMEraseBkgnd);
begin
with ThemeServices do
if ThemesEnabled and Assigned(Parent) and (csParentBackground in FControlStyle) then
begin
{ Get the parent to draw its background into the control's background. }
DrawParentBackground(Handle, Message.DC, nil, False);
end
else
begin
{ Only erase background if we're not doublebuffering or painting to memory. }
if not FDoubleBuffered or
(TMessage(Message).wParam = TMessage(Message).lParam) then
FillRect(Message.DC, ClientRect, FBrush.Handle); // , ( ),
end;
Message.Result := 1;
end;
------------------------------------------まとめ:クラスの属性を変更するとすぐに有効になります.クラスの属性に対応するSet関数を呼び出して、メッセージを送って本当にウィンドウに表示します.WM_ならメッセージは直接問題を解決することができます.フォームのタイトルを設定するなど、十分ではない場合もあります.CMを使う必要があります.メッセージはさらに、フォームの色を変更するなどの処理に役立ちます.