1

总结:

请参阅 Andreas 知识渊博的评论!

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

如下代码所示,TForm7为MDIForm窗体,TForm8为MDIChild窗体。TForm8 包含一个 alClient 对齐的面板,该面板还包含一个 TPaintBox。如果 TForm8 的面板的 ParentBackground 设置为 False,我无法从 TForm7 触发 TForm8 的paintbox 的绘制事件。我想知道为什么会发生这种情况,以及如何在不明确引用的情况下触发 TForm8 的paintbox 的绘制事件。任何建议表示赞赏!

注意:如果我Self.Repaint在 TForm8 内部调用,例如在它的 Click 事件中,可以触发 TForm8 的paintbox 的绘制事件。form8.repaint只有当我在 TForm8 外部调用时才能触发它。我想知道为什么会发生这种情况?

可能相关的 SO 页面:
如何在模式表单处于活动状态时重新绘制父表单?

包含 MDIForm 表单的单元。

    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
4

2 回答 2

5

我认为是这样的:

信不信由你,“正常”行为是,如果您重绘一个表单(或其他容器),则只有该容器被重绘,而不是其中包含的子项。然而,随着视觉主题的出现,控件得到了半透明的部分,突然之间,当重绘父控件时,您需要重新绘制子控件,仅仅是因为子控件需要重新混合到新的背景中。

我的假设(相对)很容易通过仔细检查 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;

因此, whenParentBackground设置为false,并且面板就像经典面板一样,当它的父面板是时它不会重新绘制。另一方面,如果ParentBackgroundis true,它确实会与它的父级一起重新绘制。

因此,真的没有问题;您只是期望一种不期望的行为。

所以你需要按照大卫的建议手动重新粉刷油漆盒。

于 2011-03-21T20:57:31.140 回答
1

pb1.Invalidate当您希望油漆框重新绘制自身时,您只需要调用即可。

还是我误解了你的问题?

于 2011-03-21T20:30:26.333 回答