TppShape RoundRect corner Radius
We are running RBuilder Pro 10.07 and I'm looking for a way to set the
radius of the corners for TppShape of type rtRoundRect. I see in the
CalculateDimensions that RBuilder is determining this automatically and I
was wondering if anyone has some code to set these values up as properties
instead. I don't have much experience with RBuilder so I'm not clear on
what I would need to do to modify the code with these properties myself. I
did find an old post where someone has created a new component the would do
what I want, but it was for RBuilder 6 and doesn't compile anymore.
Thanks
Chris
radius of the corners for TppShape of type rtRoundRect. I see in the
CalculateDimensions that RBuilder is determining this automatically and I
was wondering if anyone has some code to set these values up as properties
instead. I don't have much experience with RBuilder so I'm not clear on
what I would need to do to modify the code with these properties myself. I
did find an old post where someone has created a new component the would do
what I want, but it was for RBuilder 6 and doesn't compile anymore.
Thanks
Chris
This discussion has been closed.
Comments
The native TppShape does not allow altering the radius of the rounded
corners in a round rectangle. It is automatically set to one forth the size
of the smallest side.
Two options...
1. Create your own shape component and register it with ReportBuilder
adding properties to alter this value. Take a look at the custom component
example located in the \Demos\RCL directory for how this can be done. The
component will be almost identical to the existing TppShape class with added
properties and an altered CalcDimensions routine.
2. You can alter the existing RB source for a very quick fix (however this
is not recommended as a permanent solution). See the
TppShape.CalcDimentions routine located in the ppCtrls.pas file for where
the XCornerRound and YCornerRound values are set. Each one represents the
ellipse radius of the rounded corner.
--
Regards,
Nico Cizik
Digital Metaphors
http://www.digital-metaphors.com
Nico Cizik
Digital Metaphors
http://www.digital-metaphors.com
Setting the X/Y radius when running the designer from within my application
works properly as does printing to the screen and printer. But, when I
bring up the designer from within Delphi it doesn't work nor does printing
to a PDF file. I did a quick search of the source and found that
stRoundRect is referenced in the following units: ppCtrls,
ppDesignControlsEx, ppPDFRendererShape, ppPDFShape, ppPrnDev, ppRegion,
ppViewr. Do all these modules use myShape?
I had to add the Virtual declaration to TppShape.CalcDimensions in ppCtrls
in order to get my new CalcDimensions method to work. Here's the source to
my component:
Unit myShape;
Interface
Uses
Classes, ppCtrls, ppDevice, Graphics;
Type
TmyShape = Class(TppShape)
Private
FRadiusX: Double;
FRadiusY: Double;
Procedure SetRadiusX(aRadiusX: Double);
Procedure SetRadiusY(aRadiusY: Double);
Protected
Procedure PropertiesToDrawCommand(aDrawCommand: TppDrawCommand);
Override;
Public
Constructor Create(aOwner: TComponent); Override;
Procedure CalcDimensions(Var aLeft, aTop, aRight, aBottom, aRadiusX,
aRadiusY: Longint); Override;
Published
property Anchors;
property Brush;
property OnDrawCommandClick;
property OnDrawCommandCreate;
property ParentHeight;
property ParentWidth;
property Pen;
property ReprintOnOverFlow;
property Shape;
property StretchWithParent;
property UserName;
property Visible;
property Height stored False;
property Left stored False;
property Top stored False;
property Width stored False;
Property RadiusX: Double Read FRadiusX Write SetRadiusX;
Property RadiusY: Double Read FRadiusY Write SetRadiusY;
End;
Implementation
{$R myShape.res}
Uses ppClass, Types, ExtCtrls, ppUtils, ppTypes, ppDrwCmd,
Dialogs,sysutils;
Constructor TmyShape.Create(aOwner: TComponent);
Begin
Inherited Create(aOwner);
FRadiusX := 0;
FRadiusY := 0;
End;
Procedure TmyShape.SetRadiusX(aRadiusX: Double);
Begin
If aRadiusX <> FRadiusX Then
Begin
BeforePropertyChange('RadiusX');
FRadiusX := aRadiusX;
PropertyChange;
InvalidateDesignControl;
End;
End;
Procedure TmyShape.SetRadiusY(aRadiusY: Double);
Begin
If aRadiusY <> FRadiusY Then
Begin
BeforePropertyChange('RadiusY');
FRadiusY := aRadiusY;
PropertyChange;
InvalidateDesignControl;
End;
End;
Procedure TmyShape.CalcDimensions(Var aLeft, aTop, aRight, aBottom,
aRadiusX, aRadiusY: Longint);
Var
liWidth: Integer;
liHeight: Integer;
liSide: Integer;
Begin
aLeft := Pen.Width Div 2;
aTop := aLeft;
If Printing Then
Begin
liWidth := ppToScreenPixels(PrintPosRect.Right - PrintPosRect.Left,
utMMThousandths, pprtHorizontal, Nil);
liHeight := ppToScreenPixels(PrintPosRect.Bottom - PrintPosRect.Top,
utMMThousandths, pprtVertical, Nil);
End
Else
Begin
liWidth := spWidth;
liHeight := spHeight;
End;
aRight := (aLeft + liWidth) - ((Pen.Width Div 2) * 2);
aBottom := (aTop + liHeight) - ((Pen.Width Div 2) * 2);
{determine length of the shortest side, use for circles, squares and
corner rounding}
If (liWidth < liHeight) Then
liSide := liWidth
Else
liSide := liHeight;
{if shape is square or circle, make 'sides' of shape equal}
If Shape In [stSquare, stRoundSquare, stCircle] Then
Begin
{recalc top & left drawing positions based on centered side}
Inc(aLeft, (liWidth - liSide) Div 2);
Inc(aTop, (liHeight - liSide) Div 2);
{set width and height to side}
Dec(aRight, (liWidth - liSide) Div 2);
Dec(aBottom, (liHeight - liSide) Div 2);
End; {if shape has equal 'sides'}
aRadiusX := ppToScreenPixels(FRadiusX, Units, pprtHorizontal, Nil);
aRadiusY := ppToScreenPixels(FRadiusY, Units, pprtVertical, Nil);
End; {procedrue, CalcDimensions}
Procedure TmyShape.PropertiesToDrawCommand(aDrawCommand: TppDrawCommand);
Begin
Inherited PropertiesToDrawCommand(aDrawCommand);
TppDrawShape(aDrawCommand).XCornerRound := ppToMMThousandths(FRadiusX,
Units, pprtHorizontal, Nil);
TppDrawShape(aDrawCommand).YCornerRound := ppToMMThousandths(FRadiusY,
Units, pprtHorizontal, Nil);
End;
Initialization
ppRegisterComponent(TmyShape, 'Standard Components', 10, 0, 'MyShape',
HInstance);
Finalization
ppUnRegisterComponent(TmyShape);
End.
Please either post questions here or send them to
support@digital-metaphors.com, not both.
See the demo located in \Demos\RCL\ for how to create a design package and
install your new component into the Delphi IDE.
The PDF device isn't designed to handle variable corner radiuses on a round
rectangle. You have two options in this case...
1. Create a TppDrawShape descendent drawcommand and add an AsMetaFile
routine which returns the round rectangle as a native windows metafile.
Then create and register a new PDFRenderer similar to the
TppPDFRendererGeneric class that calls the AsMetaFile routine, creates a
TppPDFRendererImage and sends the metafile to be processed by the PDF
device. This is how advanced drawcommands are rendered to PDF such as RTF
and Barcode.
File to look at (ppPDFRendererGeneric, ppPDFRendererManager, ppDrwCmd,
ppRichTxDrwCmd).
2. Create and register a new TppPDFRendererShape class that processes your
new properties and draws the round rectangle directly to the PDF file. Note
that rendering graphics to a PDF take at least a general knowledge of how
PDF graphics are drawn.
(http://www.adobe.com/devnet/pdf/pdf_reference.html) Currently the round
rectangle is drawn to PDF using lines and bezier curves.
(TppPDFCanvas.RoundRectangle routine)
Files to look at (ppPDFRendererShape, ppPDFCanvas, ppPDFRendererManager).
--
Regards,
Nico Cizik
Digital Metaphors
http://www.digital-metaphors.com
Nico Cizik
Digital Metaphors
http://www.digital-metaphors.com
You are also going to need to create a new component design control for your
new shape component. See the myChkboxDesign.pas file in the \Demos\RCL\...
directory.
Currently, your component is calling the TppShapeControl.PaintDesignControl
routine to draw your round rectangle to the designer. If you look at this
code (in the ppDesignControlsEx.pas file), you will see that it typecasts
the component as a TppShape and calls CalcDimensions (which will return
incorrect values in your case). You will need to create a different design
control that calls the CalcDimensions routine of your new component rather
than TppShape. Other than that, your new control should be the same as the
shape control.
--
Regards,
Nico Cizik
Digital Metaphors
http://www.digital-metaphors.com
Nico Cizik
Digital Metaphors
http://www.digital-metaphors.com
descendant for my TMyShape control as follows:
Unit CornerRoundShapeDesign;
Interface
Uses
Windows, Classes, Graphics, Controls, Forms, ppTypes, ppDesignControls,
ppDesignControlsEx, ppInspector, CornerRoundShape;
Type
TMyShapeControl = Class(TppShapeControl)
Protected
Procedure PaintDesignControl(aCanvas: TCanvas); Override;
End;
Implementation
Uses ExtCtrls;
Procedure TMyShapeControl.PaintDesignControl(aCanvas: TCanvas);
Var
lClientRect: TRect;
llXCornerRound: Longint;
llYCornerRound: Longint;
llLeft: Longint;
llTop: Longint;
llRight: Longint;
llBottom: Longint;
lBrush: TBrush;
lPen: TPen;
lShapeType: TShapeType;
Begin
GetPropValue('Pen', lPen);
GetPropValue('Brush', lBrush);
GetPropValue('Shape', lShapeType);
lClientRect := ClientRect;
aCanvas.Pen := lPen;
aCanvas.Brush := lBrush;
TMyShape(Component).CalcDimensions(llLeft, llTop, llRight, llBottom,
llXCornerRound, llYCornerRound);
Case lShapeType Of
stRectangle,
stSquare: aCanvas.Rectangle(llLeft, llTop, llRight, llBottom);
stCircle,
stEllipse: aCanvas.Ellipse(llLeft, llTop, llRight, llBottom);
stRoundRect,
stRoundSquare: aCanvas.RoundRect(llLeft, llTop, llRight, llBottom,
llXCornerRound, llYCornerRound);
End;
End;
Initialization
TppDesignControlFactory.RegisterDesignControlClass(TMyShape,
TMyShapeControl);
Finalization
TppDesignControlFactory.UnRegisterDesignControlClass(TMyShape);
End.
I have added this to a runtime only package in the same way that the
myChkBoxDesign and myChkDlg are added to rbUSERDesign9.bpl. But as this is
a runtime only package, it cannot be installed in to the IDE so how does my
new control above get instantiated when the Report Designer is started from
within the Delphi IDE?
Thanks
Chris
The Demos\RCL folder contains a complete example for the Checkbox
components. There are 3 packages. The 'dcl' prefixed packaged is the
design-time only package. There is also a package for the component and
another package for the Designer. I recommend reviewing each the .pas and
.dpk files contained in the folder - they are all essential to building a
complete solution.
--
Nard Moseley
Digital Metaphors
www.digital-metaphors.com
Best regards,
Nard Moseley
Digital Metaphors
www.digital-metaphors.com