Solved

My own TGraphicControl with Autosize option

Posted on 2004-10-03
7
447 Views
Last Modified: 2008-01-09
hi!
can any experts tell me how to solve the following dillema
I made a new component based on TGraphicControl :

procedure TDarkRotateLabel.paint;
var
  LabelImage   : TBitmap;
  FRenderImage : TBitmap;
  Center       : TPoint;
begin
  inherited;
  if update then
  begin
    LabelImage   := TBitmap.Create;
    FRenderImage := TBitmap.Create;
    with LabelImage do
    try
      if (Self.Transparent) then
      Transparent := true;

      Canvas.Font.Assign(FFont);
      PixelFormat := pf24bit;
      Width  := Canvas.TextWidth(Caption);
      Height := Canvas.TextHeight(Caption);
      Canvas.TextOut(0,0,caption);

      with FRenderImage do
      begin
        if self.Transparent then
        Transparent := true;

        Width  := self.Width;
        height := self.Height;
        PixelFormat := pf24bit;
      end;

      with TJvPaintFX.Create do
      try
        Center.x := (self.Width  div 2);
        Center.y := (self.Height div 2);
        SmoothRotate(LabelImage,FRenderImage, Center.X, Center.Y, FAngle);
      finally
        free;
      end;

      if autosize then
      begin
       { THIS IS WHERE I NEED TO CALCULATE THE AUTOSIZE }    
        self.width := Abs(Trunc(width * cos(fAngle*Pi/180))) + Abs(Trunc(height * sin(fangle*Pi/180)));
        self.height := Abs(Trunc(height * sin(fAngle*Pi/180))) + Abs(Trunc(height * cos(fAngle*Pi/180)));

        self.canvas.Draw(0,0,FRenderImage);
      end else
      self.canvas.Draw(0,0,FRenderImage);
    finally
      FreeAndNil(FRenderImage);
      FreeAndNil(LabelImage);
      free
    end;
  end;
end;

// --------------------------------------------------------

How to make it  act like the TLabel's autosize property?.. ii tought of a "solution" where I can "auto crop"  the excessive whites around the rect of the actual FRendered image.. but I have no idea how to do this....

i searched through various solutions on googlee, but most of them did not exactly what I wanted..



0
Comment
Question by:joepezt
  • 4
  • 3
7 Comments
 
LVL 1

Expert Comment

by:Bart_Thomas
ID: 12216981
It is better when you seperate the two. Painting the rotated bitmap is
different from calculating how big your control must be. Whenever the
Caption or Angle changes you can recalculate how your controls sizes.

And you don't need the TJvPaintFX. Windows has a LOGFONT (TLogFont
in Delphi) which can paint rotated text. It can even anti-alias the text
for you.

Bart Thomas
0
 
LVL 2

Author Comment

by:joepezt
ID: 12217881
hmm yes, I noticed this when setting my control to transparent, i got white "dust" on the edges...

logfont, hmmm
0
 
LVL 1

Accepted Solution

by:
Bart_Thomas earned 50 total points
ID: 12219498
A good place to autosize your control can be the (public) SetBounds function:

procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;

What you can do is create a DoResize procedure who calculates the correct Width and Height.

  DoResize (AWidth,AHeight);
  inherited SetBounds (ALeft,ATop, AWidth,AHeight);

Maybe you know how to calculate the correct Width and Height. If don't, here's some code:

procedure TRotated.DoResize(var AWidth,AHeight: Integer);
var
  sz: TSize;
  x,y: array[0..3] of Double;
  px,py,minx,miny,maxx,maxy: Double;
  p,q,i: Integer;
  logFont: TLogfont;
begin
  GetObject(Canvas.Font.Handle, SizeOf(TLogFont), @logfont);
  logfont.lfQuality := ANTIALIASED_QUALITY;
  logfont.lfEscapement := Trunc (FAngle * 10);
  logfont.lfOrientation := Trunc (FAngle * 10);
  Canvas.Font.Handle := CreateFontIndirect(logfont);

  sz := Canvas.TextExtent(FCaption);
  if (sz.cx = 0) or (sz.cy = 0) then
    Exit;

  x[0] := -sz.cx/2;
  y[0] := -sz.cy/2;

  x[1] := sz.cx/2;
  y[1] := -sz.cy/2;

  x[2] := sz.cx/2;
  y[2] := sz.cy/2;

  x[3] := -sz.cx;
  y[3] := sz.cy/2;

  // x' = x cos (a)  - y sin (a)
  // y' = x sin (a)  + y cos (a)
  for i := 0 to 3 do
    Rotate (x[i],y[i], -FAngle);

  minx := x[0];
  miny := y[0];
  maxx := x[0];
  maxy := y[0];

  for i := 0 to 3 do
  begin
    minx := Min (minx,x[i]);
    miny := Min (miny,y[i]);
    maxx := Max (maxx,x[i]);
    maxy := Max (maxy,y[i]);
  end;

  AWidth := Trunc (maxx - minx);
  AHeight := Trunc (maxy - miny);
  px := AWidth / 2;
  py := AHeight / 2;
  FTextPosition.X := Trunc(x[0]+ px);
  FTextPosition.Y := Trunc(y[0] + py);
end;
0
Gigs: Get Your Project Delivered by an Expert

Select from freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely and get projects done right.

 
LVL 1

Expert Comment

by:Bart_Thomas
ID: 12219567
Ow... I fogot a little detail!
You must use a true type font.
0
 
LVL 2

Author Comment

by:joepezt
ID: 12219927
altho, I did get the original control to work, by creating a new class descendand of TCustomControl
and sending a postmessage WM_USER + 1 with the pointer integer of "self" with invalidate

but I will accept your sollution as well
0
 
LVL 1

Expert Comment

by:Bart_Thomas
ID: 12220438
Allright, thanks.

I noticed you recreate a bitmap with the caption every time you repaint your control. That's can be avoided by adding the LabelImage to the class as private field and repaint it when the caption changes:

  TDarkRotateLabel = class (TCustomControl)
  private
    FCaption: String;
    FLabelImage: TBitmap;

    procedure SetCaption(const Value: String);
  protected
  public
    constructor Create (AOwner: TComponent); override;
    destructor Destroy; override;
    property Caption: String read FCaption write SetCaption;
  end;

{ TDarkRotateLabel }

constructor TDarkRotateLabel.Create(AOwner: TComponent);
begin
  inherited;
  FLabelImage := TBitmap.Create;
end;

destructor TDarkRotateLabel.Destroy;
begin
  FLabelImage.Free;
  inherited;
end;

procedure TDarkRotateLabel.SetCaption(const Value: String);
var
  sz: TSize;
  rect; TRect;
begin
  FCaption := Value;

  FLabelImage.Canvas.Font := Font;
  sz := FLabelImage.Canvas.TextExtent(FCaption);
  FLabelImage.Width := sz.cx;
  FLabelImage.Height := sz.cy;

  SetRect (rect, 0,0,sz.cx,sz.cy);

  FLabelImage.Canvas.Brush.Color := clWhite;
  FLabelImage.Canvas.Brush.Style := bsSolid;
  FLabelImage.Canvas.FillRect(rect);

  SetBkMode (FLabelImage.Canvas.Handle, TRANSPARENT);
  SetTextColor (FLabelImage.Canvas.Handle, clBlack);
  FLabelImage.Canvas.TextOut(0,sz.cy, FCaption);
end;

You even can rotate the text and only blit the image to the target in the Paint-procedure.
0
 
LVL 2

Author Comment

by:joepezt
ID: 12220676
ah, thanks!, I will see if i can use some of this. the setbkmode might be usefull...
I do save my lavelimage to a temporary image declared in privatesection, and if set update := true when I need to invalidate to be sure I can reupdate my image. if update = false then just repaint the old image..
0

Featured Post

Live: Real-Time Solutions, Start Here

Receive instant 1:1 support from technology experts, using our real-time conversation and whiteboard interface. Your first 5 minutes are always free.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
calling Tcolordialog in dll make the form disappear 8 111
how to center only a line in richedit? 4 56
creating threads in delphi 1 101
Multi-layered image in FireMonkey 9 31
The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
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…
Two types of users will appreciate AOMEI Backupper Pro: 1 - Those with PCIe drives (and haven't found cloning software that works on them). 2 - Those who want a fast clone of their boot drive (no re-boots needed) and it can clone your drive wh…
Although Jacob Bernoulli (1654-1705) has been credited as the creator of "Binomial Distribution Table", Gottfried Leibniz (1646-1716) did his dissertation on the subject in 1666; Leibniz you may recall is the co-inventor of "Calculus" and beat Isaac…

785 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