Solved

TPanel.Canvas?

Posted on 2002-03-10
10
3,125 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
What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

 

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

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

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…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…

744 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

12 Experts available now in Live!

Get 1:1 Help Now