Solved

TPanel.Canvas?

Posted on 2002-03-10
10
3,153 Views
Last Modified: 2012-08-14
I know how to draw on the canvas of a form but is it possible to do the same with a Panel (or Tabsheet)?

if so, give a short example please.
0
Comment
Question by:d32coder
  • 6
  • 3
10 Comments
 

Expert Comment

by:Kelmi
ID: 6854582
You can make and a new panel component which has an OnPaint event and Canvas property. Here is an example:

unit paintpanel;

interface

uses
  ExtCtrls, Classes;

type
  TPaintPanel = class(TPanel)
  private
    FOnPaint: TNotifyEvent;  
  protected
    procedure Paint; override;
  public
    property Canvas;
  published
    property OnPaint: TNotifyEvent read FOnPaint write FOnPaint;
  end;

  procedure Register;

implementation

{ Register component }

procedure Register;
begin
  RegisterComponents('Samples', [TPaintPanel]);
end;

{ TPaintPanel }

procedure TPaintPanel.Paint;
begin
  inherited Paint;
  if Assigned(FOnPaint) then FOnPaint(Self);
end;

end.
0
 
LVL 9

Expert Comment

by:ginsonic
ID: 6854649
listening
0
 

Expert Comment

by:Kelmi
ID: 6854717
I mean: "You can make and INSTALL a new..."


0
 
LVL 8

Expert Comment

by:TOndrej
ID: 6854811
All TControl descendants have Canvas property which is protected by default, although in some cases the descendant classes do promote its visibility to public.

To access a protected property of a class, you can use an old trick:

type
  THackPanel = class(TPanel);

with THackPanel(Panel1).Canvas do
  ...

in this example, Panel1 is a 'normal' TPanel. The typecast allows you to access its protected properties.

HTH
TOndrej
0
 

Expert Comment

by:Kelmi
ID: 6854842
Useful tip, TOndrej! But if you want to paint on panel's canvas, you should also override its Paint procedure, or...?
0
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 

Expert Comment

by:Kelmi
ID: 6854846
Useful tip, TOndrej! But if you want to paint on panel's canvas, you should also override its Paint procedure, or...?
0
 
LVL 8

Accepted Solution

by:
TOndrej earned 50 total points
ID: 6854995
> if you want to paint on panel's canvas, you should also
> override its Paint procedure, or...?

No, strictly speaking, to paint on a canvas you don't need anything else than to use TCanvas methods, or Windows GDI APIs with the DC handle.

A different problem is if you want to do your painting every time the panel repaints itself (ie. you don't want your painting to disappear the next time the control gets invalidated and repaints itself). In that case you need to make sure that your painting is done again _every time_ the control (re)paints itself.

In a TForm descendant, you can simply use the form's OnPaint event which is called for you automatically every time the form is painted.
For controls like TPanel which don't have an OnPaint event, you have two options:

1. Create a descendant and override its Paint method, as you have shown.
This one is useful when the descendant is going to be reused in other projects.

2. Subclass the panel to intercept WM_PAINT messages, for example:

type
  TFormTest = class(TForm)
    Panel1: TPanel;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    FPanelWndProc: TWndMethod;

    procedure PanelWndProc(var Message: TMessage);
  public
  end;


procedure TFormTest.FormCreate(Sender: TObject);

begin
  // remember the panel's original window procedure
  FPanelWndProc := Panel1.WindowProc;
  // subclass the panel
  Panel1.WindowProc := PanelWndProc;
end;

procedure TFormTest.FormDestroy(Sender: TObject);
begin
  // restore the panel's original window procedure
  Panel1.WindowProc := FPanelWndProc;
  FPanelWndProc := nil;
end;

type
  THackPanel = class(TPanel);

procedure TFormTest.PanelWndProc(var Message: TMessage);
const
  GridSize = 8;
var
  X, Y: Integer;
begin
  // call the panel's original window procedure
  FPanelWndProc(Message);
  // do your own painting
  // this example draws a grid on the panel
  if Message.Msg = WM_PAINT then
    with THackPanel(Panel1) do
    begin
      X := 0;
      while X <= ClientWidth do
      begin
        Y := 0;
        while Y <= ClientHeight do
        begin
          Canvas.Pixels[X, Y] := clNavy;

          Inc(Y, GridSize);
        end;

        Inc(X, GridSize);
      end;
    end;
end;

This can come handy when you don't want to create a new descendant for just one very specific case; you want to create the control and set its properties at designtime but not register it into the component palette (because it's very special and will not be used in other projects).

HTH
TOndrej
0
 

Expert Comment

by:Kelmi
ID: 6855077
I can see your point.

Do you know why protected properties become accessible when you define a new type like:

type
 THackPanel = class(TPanel);

If you want those protected properties to stay protected (I mean not accessible), is the only way to redeclare them as protected?
0
 
LVL 8

Expert Comment

by:TOndrej
ID: 6855106
> Do you know why protected properties become accessible
> when you define a new type like:

> type
> THackPanel = class(TPanel);

The statement above declares a new descendant class.

By definition, a protected property is visible to the class in which it is declared and to all descendant classes; plus also to any code within the same unit after the declaration.

> If you want those protected properties to stay protected
> (I mean not accessible), is the only way to redeclare
> them as protected?

No need to do anything, see above.
In the example above, we have not changed visibility of any properties.
Our trick was to typecast Panel (an instance of TPanel) to THackPanel which is technically incorrect (Panel1 is _not_ THackPanel) but safe (because THackPanel does not introduce any changes) which allowed us to access the protected Canvas.
0
 

Expert Comment

by:Kelmi
ID: 6855128
Thanks for the information. That trick is pretty useful.
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
This Micro Tutorial will give you a basic overview how to record your screen with Microsoft Expression Encoder. This program is still free and open for the public to download. This will be demonstrated using Microsoft Expression Encoder 4.
This tutorial gives a high-level tour of the interface of Marketo (a marketing automation tool to help businesses track and engage prospective customers and drive them to purchase). You will see the main areas including Marketing Activities, Design …

863 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

22 Experts available now in Live!

Get 1:1 Help Now