2011-03-21 39 views
1

綜述:如何重繪一個MDIChild窗體時,將MDIChild本身含有的容器,如TPanel有排列:= alClient和ParentBackground:=假

請參閱安地列斯懂行的意見!

==========================================

如下面的代碼所示,TForm7是MDIForm格式,TForm8是MDIChild格式。 TForm8包含一個alClient對齊面板,它還包含一個TPaintBox。如果TForm8的面板的ParentBackground設置爲False,我不能從TForm7觸發TForm8的paintbox的繪畫事件。我想知道爲什麼會發生這種情況,以及如何觸發TForm8的paintbox的繪畫事件,而不會明確地引用它。任何建議表示讚賞!

注:如果我叫 Self.Repaint withint TForm8,例如其Click事件中,可以觸發TForm8的顏料盒的Paint事件。只有當我在TForm8之外呼叫 form8.repaint時才能觸發它。我想知道爲什麼會發生這種情況?

可能相關的SO網頁:包含mdi窗體形式
How to repaint a parent form while a modal form is active?

單位。

unit Unit7; 

    interface 

    uses 
     Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
     Dialogs; 

    type 
     TForm7 = class(TForm) 
     procedure FormShow(Sender: TObject); 
     procedure FormClick(Sender: TObject); 

     end; 

    var 
     Form7: TForm7; 

    implementation 

    {$R *.dfm} 

    uses 
     Unit8; 

    procedure TForm7.FormShow(Sender: TObject); 
    begin 
     TForm8.Create(Self); 
    end; 

    procedure TForm7.FormClick(Sender: TObject); 
    begin 
     TForm8(ActiveMDIChild).Repaint; 
    end; 

    end. 

上述單位的dfm。

object Form7: TForm7 
     Left = 0 
     Top = 0 
     Caption = 'Form7' 
     ClientHeight = 379 
     ClientWidth = 750 
     Color = clBtnFace 
     Font.Charset = DEFAULT_CHARSET 
     Font.Color = clWindowText 
     Font.Height = -11 
     Font.Name = 'Tahoma' 
     Font.Style = [] 
     FormStyle = fsMDIForm 
     OldCreateOrder = False 
     OnClick = FormClick 
     OnShow = FormShow 
     PixelsPerInch = 96 
     TextHeight = 13 
    end 

包含MDIChild表單的單元。

unit Unit8; 

    interface 

    uses 
     Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
     Dialogs, ExtCtrls; 

    type 
     TForm8 = class(TForm) 
     pb1: TPaintBox; 
     pnl1: TPanel; 
     procedure pb1Paint(Sender: TObject); 
     procedure pb1Click(Sender: TObject); 
     private 
     fCounter: Integer; 

     end; 

    implementation 

    {$R *.dfm} 

    procedure TForm8.pb1Click(Sender: TObject); 
    begin 
     Self.Repaint; 
    end; 

    procedure TForm8.pb1Paint(Sender: TObject); 
    begin 
     Self.pb1.Canvas.TextOut(30, 30, IntToStr(Self.fCounter)); 
     Self.fCounter := Self.fCounter + 1; 
    end; 

    end.  

上述單位的dfm。

object Form8: TForm8 
     Left = 0 
     Top = 0 
     Caption = 'Form8' 
     ClientHeight = 226 
     ClientWidth = 233 
     Color = clBtnFace 
     Font.Charset = DEFAULT_CHARSET 
     Font.Color = clWindowText 
     Font.Height = -11 
     Font.Name = 'Tahoma' 
     Font.Style = [] 
     FormStyle = fsMDIChild 
     OldCreateOrder = False 
     Visible = True 
     PixelsPerInch = 96 
     TextHeight = 13 
     object pnl1: TPanel 
     Left = 0 
     Top = 0 
     Width = 233 
     Height = 226 
     Align = alClient 
     ShowCaption = False 
     TabOrder = 0 
     object pb1: TPaintBox 
      Left = 1 
      Top = 1 
      Width = 231 
      Height = 224 
      Align = alClient 
      OnClick = pb1Click 
      OnPaint = pb1Paint 
      ExplicitLeft = 56 
      ExplicitTop = -64 
      ExplicitWidth = 105 
      ExplicitHeight = 105 
     end 
     end 
    end 
+3

一邊。你爲什麼叫'Repaint'?通常情況下,您調用Invalidate,Invalidate調用InvalidateRect,InvalidateRect反過來發布WM_PAINT消息。只有在應用程序閒置後纔會抽取消息隊列,纔會處理此消息。這是一種更有效的做事方式,因爲它最大限度地減少了實際繪製的次數。 – 2011-03-21 20:55:32

回答

5

我覺得是這樣的話:

信不信由你,「正常」的行爲是,如果你重新繪製一個表格(或其他容器),僅該容器被粉刷一新,而不是孩子所含在裏面。然而,隨着視覺主題的來臨,控制了半透明的部分,突然你需要重繪子控件當父重繪,只是因爲孩子需要reblend到新的背景。

我的假設是(相對)通過審查的VCL源代碼,例如容易驗證

procedure TWinControl.CMInvalidate(var Message: TMessage); 
begin 
    { Removed irrelevant code to avoid copyvio issues. } 
     InvalidateRect(WindowHandle, nil, not (csOpaque in ControlStyle)); 
     { 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 
      Controls[I].Invalidate; 
    { Removed irrelevant code to avoid copyvio issues. } 
end; 

因此,當ParentBackground設置爲false,面板bahaves像經典面板中,當它的父是它不重新繪製。在另一方面,如果ParentBackgroundtrue,它得到與其父一起粉刷一新。

因此是沒有問題的,真的,你只是期望一種不可預料的行爲。

因此,您需要按照David的建議手動重新繪製顏料盒。

+0

@Andreas:非常感謝您的寶貴意見! – SOUser 2011-03-21 21:00:51

+0

@Andreas:你可以評論哪些是推薦的,ParentBackground:= True或False?我將ParentBackground保留爲false,僅僅因爲我認爲通過將ParentBackground設置爲false,我可以阻止Parent繪製Parent的背景,以避免開銷和/或閃爍。你能否幫忙評論這是否屬實? – SOUser 2011-03-21 21:04:23

+1

@Xichen:這可能不算什麼開銷,但我確定'ParentBackground:= False'勝過其他選項。但是,如果你使用主題,例如,如果你在'TPageControl'中放置了'TPanel',那麼你確實需要父背景! – 2011-03-21 21:06:57

1

你只需要調用pb1.Invalidate當你想讓油漆盒重新繪製自己。

還是我誤解你的問題?

+1

@David:我想你沒有看完他的整個問題。他想通過調用 *父窗體*的'Repaint'(或'Invalidate'),即包含帶有顏料框的面板的MDI子窗體來重新繪製顏料盒。除非面板將'ParentBackground'設置爲'true',否則這將起作用。爲什麼OP希望這樣做,我不知道,但我認爲至少是這個問題。 [當然,我沒有失望。] – 2011-03-21 20:44:57

+1

@Andreas西晨可能希望以這種方式使塗料盒失效,但如果它不起作用,那麼它不會這樣做,那麼按我建議的方式做工作。我認爲! – 2011-03-21 20:46:43

+1

@David:是的,你的方法有效。 – 2011-03-21 20:48:26