Reputation: 3852
Summarization:
Please see Andreas' knowledgeable comments!
==========================================
As shown in the following code, TForm7 is the MDIForm form, TForm8 is the MDIChild form. TForm8 contains an alClient aligned panel, which further contains a TPaintBox. If the TForm8's panel's ParentBackground is set to False, I cannot trigger TForm8's paintbox's paint event from TForm7. I am wondering why would this happen, and how can I trigger TForm8's paintbox's paint event without exlicitly refering to it. Any suggestion is appreciated!
Note: If I call Self.Repaint
withint TForm8, for example inside its Click event, TForm8's paintbox's paint event can be triggered. It cannot be triggered only when I call form8.repaint
outside TForm8. I am wondering why would this happen?
Possibly relevant SO pages:
How to repaint a parent form while a modal form is active?
Unit that contains the MDIForm form.
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 of the above Unit.
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
Unit that contains the MDIChild form.
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 of the above Unit.
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
Upvotes: 1
Views: 1248
Reputation: 108963
I think this is the case:
Believe it or not, the "normal" behaviour is that, if you repaint a form (or some other container), only that container gets repainted, not the children contained in it. However, with the advent of visual themes, controls got semi-transparent parts, and all of a sudden you need to repaint the child controls when the parent is redrawn, simply because the children need to reblend into the new background.
My hypothesis is (relatively) readily validated by scrutinizing the VCL source code, e.g.
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;
Therefore, when ParentBackground
is set to false
, and the panel bahaves like a classic panel, it isn't repainted when its parent is. On the other hand, if ParentBackground
is true
, it does get repainted along with its parent.
Hence there is no problem, really; you simply expect a behaviour that isn't to be expected.
So you need to repaint the paint box manually, by following David's advice.
Upvotes: 5
Reputation: 612993
You just need to call pb1.Invalidate
when you want the paint box to re-draw itself.
Or am I misunderstanding your question?
Upvotes: 1