Home Component Writing
New Blog Posts: Merging Reports - Part 1 and Part 2

Why use TppDrawCommand?

edited April 2003 in Component Writing
HI,
Since I'm not familar with the print engine, so Can anybody explain to me,
Why we need the TppDrawCommand class to print on the preview device, printer
device or other device, since these device have Canvas, why we don't just
call the method PaintDesignControl of TppCustomCompnent class to paint on
these device, rather than use PaintDesignControl for design purpose and
using DrawCommand class for print, preview purpose. e.g. I'm trying to
design a checkbox with a description beside it. after I do the research, I
finally give up, since by using RB componet structure, I can't just simple
draw a rectangle and a caption because there is no corresponding draw
command class for it. I have to create a rectangle shape component + a
label component, which I think wasting resources and could make the report
more big.

Best Regards,

William

Comments

  • edited April 2003
    ReportBuilder's architecture uses draw commands, much like a windows
    metafile uses instructions to draw. The draw commands are instructions on
    what to draw, not how to draw it. This allows for an open device
    architecture, where each device takes the same draw command and renders it
    on any device context (printer, text file, image or other format, such as
    XHTML, PDF or XLS). This doesn't tie you down to having only TCanvas support
    on a device class. If you wanted to, you could create an output device that
    sent each page of the report as a separate email, because you aren't tied to
    a canvas for drawing. The devices which have canvas' are implmented by
    drawing on the canvas such as the screen device.

    You'll need to create two draw commands. One for the shape and one for the
    label.


    Cheers,

    Jim Bennett
    Digital Metaphors


  • edited April 2003
    Thanks, Jim, But what should I do for the draw command, I put following code
    in the overridden PropertiesToCommand mthod:

    inherited PropertiesToDrawCommand(aDrawCommand);
    {make sure the drawcommand is of the appropriate class}
    if not(aDrawCommand is TppDrawText) and not (aDrawCommand is TppDrawShape)
    then Exit;
    begin
    CalcDimensions(llLeft, llTop, llRight, llBottom, llXCornerRound,
    llYCornerRound);
    llLeft := PrintPosRect.Left + ppToMMThousandths(llLeft, utScreenPixels,
    pprtVertical, nil);
    llTop := PrintPosRect.Top + ppToMMThousandths(llTop, utScreenPixels,
    pprtVertical, nil);
    llRight := PrintPosRect.Left + ppToMMThousandths(llRight,
    utScreenPixels, pprtVertical, nil);
    llBottom := PrintPosRect.Top + ppToMMThousandths(llBottom,
    utScreenPixels, pprtVertical, nil);
    llXCornerRound := ppToMMThousandths(llXCornerRound, utScreenPixels,
    pprtVertical, nil);
    llYCornerRound := ppToMMThousandths(llYCornerRound, utScreenPixels,
    pprtVertical, nil);

    lDrawShape := TppDrawShape(aDrawCommand);
    lDrawShape.Pen.Color := clBlack;
    lDrawShape.ShapeType := stRectangle;
    lDrawShape.Left := llLeft;
    lDrawShape.Top := llTop;
    lDrawShape.Height := CheckBoxSize;
    lDrawShape.Width := CheckBoxSize;
    lDrawShape.XCornerRound := 0;
    lDrawShape.YCornerRound := 0;
    if FChecked then
    lDrawShape.Brush.Color := clBlack
    else
    lDrawShape.Brush.Color := clBtnShadow;
    end;
    if aDrawCommand is TppDrawText then
    begin
    lDrawText := TppDrawText(aDrawCommand);
    {set the position of the text on the page}
    lDrawText.Left := PrintPosRect.Left + CheckBoxSize;
    lDrawText.Top := PrintPosRect.Top;
    lDrawText.Height := PrintPosRect.Bottom - PrintPosRect.Top;
    lDrawText.Width := PrintPosRect.Right - PrintPosRect.Left;
    {set the drawtext properties so the visual represention of the check box
    will
    be correct when the command is rendered by the receiving Device
    (ScreenDevice
    for Print Preview form, PrinterDevice when printing to printer, etc.)}
    lDrawText.Alignment := taLeftJustify;
    lDrawText.AutoSize := True;
    lDrawText.Color := Color;
    lDrawText.Font.Height := spHeight;
    lDrawText.Text := Caption;
    lDrawText.Transparent := Transparent;
    lDrawText.WordWrap := False;
    end;

    But result on the preview form, it only prints the caption, no check box, so
    what am I missing?, Could you please correct me? the check box component
    is inherited from TppCustomComponent.

    William


  • edited April 2003
    Sorry, my fault. You have to assign the page object of the draw command you
    create which isn't passed in the parameter of this routine. For example, in
    our source the page object is assigned after this routine is called in the
    ancestor. Here is the code, perhaps this will give you abetter
    understanding of what is happening when this routine is overridden by you
    and it is called:

    {---------------------------------------------------------------------------
    ---}
    { TppPrintable.CreateDrawCommand }

    procedure TppPrintable.CreateDrawCommand(aPage: TppPage);
    var
    lDrawCommand: TppDrawCommand;
    lParams: TraParamList;
    begin

    if (FDrawCommandClass = nil) then Exit;

    {create the draw command}
    lDrawCommand := FDrawCommandClass.Create(nil);

    {transfer properties to draw command}
    PropertiesToDrawCommand(lDrawCommand); <-- Here is the call, so most
    likely your draw command class is always TppDrawText

    {assign click event handler, do this after create}
    lDrawCommand.Clickable := Assigned(FOnDrawCommandClick) or
    IsActiveNotify(ciPrintableDrawCommandClick);
    lDrawCommand.OnClick := DrawCommandClickEvent;

    {assign the page rect - used for clipping}
    lDrawCommand.ClipRect := aPage.PageDef.PageRect;

    {trigger event}
    if Assigned(FOnDrawCommandCreate) then FOnDrawCommandCreate(Self,
    lDrawCommand);

    {assign draw command to page, do this last, so drawcommand is properly
    classified}
    lDrawCommand.Page := aPage;

    lParams := TraTppPrintableRTTI.GetParams('OnDrawCommandCreate');
    lParams.CreateValuePointer(0, lDrawCommand);

    SendEventNotify(Self, ciPrintableDrawCommandCreate, lParams);

    lParams.Free;

    end; {procedure, CreateDrawCommand}

    So if you want to add a draw command, you'll have to create a TppDrawShape,
    then reference Report.Engine.Page as the report is generating in order to
    add a draw command to the page. lDrawShape.Page := Report.Engine.Page. This
    call can't be made from inside PropertiesToDrawCommand, unless you create a
    global function to let you get at the current TppReport object, but this
    isn't exactly OO. After thinking about this more, the other (probably
    better) alternative is to create a new draw command class that can draw a
    shape and text all in one. This way you can create one object and it can
    draw a shape and some text. Override the Draw routine of the draw command
    descendent in order to let the draw command class draw itself rather than
    let the device determine how to draw the draw command. See ppDevice.pas for
    the TppDrawCommand ancestor interface section or check out our help file on
    the draw command classes and members.


    Cheers,

    Jim Bennett
    Digital Metaphors


This discussion has been closed.