Link to home
Start Free TrialLog in
Avatar of ittay
ittay

asked on

non databased reports

hi,

i want to generate reports which aren't databased (so there's no use for
reportsmith etc)
i also need to provide a preview of the report.

what i thought of doing is this: because the report can be long, i'll use a
TScrollBox, in it i'll put all the components needed for the report and
then the user can scroll up/down the report.

the problem starts when i want
to print it. i don't want to create a second form with the same components
and print it since it'll be measy. what i want is to copy the contents of
the ScrollBox, AS AN IMAGE, to the printer's canvas and print it (forget
for a minute the scaling problem) but a TScrollBox component has no canvas!
so i can't copy it's contents! (remember that i can't use the form's canvas
since not all the report is visual - the user scrolls up/down to see it).

after this long introduction, here's my question: do you know of a (free)
component that is a TScrollBox with a canvas, or can you tell me how to
create one, or do you have a better idea as to how to achieve what i
described?

thanks in advance,
ittay
Avatar of pivar
pivar
Flag of Sweden image

Hi,

You can place a TPaintBox on the TScrollBox, the paintbox got a canvas that you can use.

/pivar
Avatar of ittay
ittay

ASKER

pivar's answer doesn't work. if i try to copy the Canvas of the TPaintBox, it copies what's seen on the SCREEN (the TPaintBox is partialy hidden), and NOT the PaintBox's contents (what's hidden)
If you use a TImage instead of a TPaintBox, it should work.  However, a large TImage will consume a lot of memory.

I don't think this will solve your problem anyway, because you'd still have to draw each control onto the TImage.

Bear in mind that when you get the canvas of a ScrollBox, you will only get that part which is visible.  For example, if you create a new scrollbox as follows:

TNewScrollBox = class(TScrollBox)
private
      FCanvas: TControlCanvas;
      function GetCanvas: TCanvas;
public
      constructor Create(AOwner: TComponent); override;
      destructor Destroy; override;
      property Canvas: TCanvas read GetCanvas;
end;

constructor TNewScrollBox.Create(AOwner: TComponent);
begin
      inherited Create(AOwner);
      FCanvas := TControlCanvas.Create;
      FCanvas.Control := Self;
end;

destructor TNewScrollBox.Destroy;
begin
      FCanvas.Free;
      inherited;
end;

function TNewScrollBox.GetCanvas: TCanvas;
begin
      Result := FCanvas;
end;

When you get the NewScrollBox's canvas, it will only return the part that is visible, NOT the entire canvas.

Does every control that you put onto your ScrollBox have a canvas?

JB
Avatar of ittay

ASKER

to JimBob:

that's exactly my problem!

forget the solution i was thinking of. what i need is this:
i need to be able to generate different, visualy complex, reports and i need the ability to have them previewed to the user (that's what the scrollbox's for).

because i have several reports, and they aren't simple to draw, i can't draw them directly to the printer (i need a generic way of making the reports). i'm looking for a way so that i can put the report's components (labels, images, stringgrids...) on a form (or anything else), fill them with the data i need, show the report to the user (preview) and then print it.

any suggestions will be greatly appriciated.
ittay
Hi ittay.  I was playing with a form with a scrollbox (boxTest) and a TImage (imgTest).  I set imgTest.AutoSize to True.  I put a few panels and stringgrids into the scrollbox.  There was also a button (Button1) which executed the following code:

procedure TForm1.Button1Click(Sender: TObject);
var
      i: Integer;
      Bmp: TBitmap;
      WinCtl: TWinControl;
begin
      Bmp := TBitmap.Create;
      try
            Bmp.Width := 1000;
            Bmp.Height := 1000;
            for i := 0 to boxTest.ControlCount - 1 do
                  if (boxTest.Controls[i] is TWinControl) then
                        begin
                              WinCtl := TWinControl(boxTest.Controls[i]);
                              WinCtl.PaintTo(Bmp.Canvas.Handle, WinCtl.Left, WinCtl.Top);
                        end;
            imgTest.Picture.Assign(Bmp);
      finally
            Bmp.Free;
      end;
end;


This code takes the entire scrollbox's canvas and pops it into the TImage.  It only works for TWinControls (because they have a PaintTo method).

Does this get you any closer to your goal?
JB
P.S.  Sorry about the indentation of the code.  I cut & pasted from the Delphi IDE and it looked fine in the Experts-Exchange memo box, but when I hit submit the indentation is gone.  What am I doing wrong???
I would propose that you use the QuickReport components. Although they are primarily intended for making DB based reports, they can be used for what you intend too.

With QuickReports you get Preview for free (it is a method in the  TQuickRep component), as well as sensible page breaking for long reports.

Rather than associating a DataSource with the report, you write your own handlers for the OnNeedData event. This allows you to supply the report with data directly from the program.

Hope this will help.

AndersWP
Avatar of ittay

ASKER

to JimBob:

your solution sounds great, only i don't have a PainTo method (you're probably using delphi 2.0 or 3.0, i NEED to use 1.0)

thanks
ittay
Avatar of ittay

ASKER

to AndersWP:
i've downloaded the evaluation version of quickreport and played with it a bit. here are the reasons why it's not good for me:
1. it's too complex. what i need isn't a report which does a lot of data manipulation but rather one that does 'visual manipulation', by that i mean it has some bitmaps, lables, stringgrids etc.
2. writing the code for the OnNeedData event will, i think make it even more complex.
3. i'm afraid that by using database aware components in my application i'll need all of delphi's dll's that manage databases. this will make my program larger and also will cause problems in installing it.
4. it costs money.

thanks anyway,
ittay

p.s. if you know of a component which has a preview method (so i can drop components on it and then preview them to the user), tell me about it.

Avatar of ittay

ASKER

Adjusted points to 180
Hi ittay.
You are correct - I am using Delphi 3.
I know that it's not exactly what you are looking for, but here is the code for Delphi 3's PaintTo method:

procedure TWinControl.PaintTo(DC: HDC; X, Y: Integer);
var
  I, EdgeFlags, BorderFlags, SaveIndex: Integer;
  R: TRect;
begin
  Include(FControlState, csPaintCopy);
  SaveIndex := SaveDC(DC);
  MoveWindowOrg(DC, X, Y);
  IntersectClipRect(DC, 0, 0, Width, Height);
  BorderFlags := 0;
  EdgeFlags := 0;
  if GetWindowLong(Handle, GWL_EXSTYLE) and WS_EX_CLIENTEDGE <> 0 then
  begin
    EdgeFlags := EDGE_SUNKEN;
    BorderFlags := BF_RECT or BF_ADJUST
  end else
  if GetWindowLong(Handle, GWL_STYLE) and WS_BORDER <> 0 then
  begin
    EdgeFlags := BDR_OUTER;
    BorderFlags := BF_RECT or BF_ADJUST or BF_MONO;
  end;
  if BorderFlags <> 0 then
  begin
    SetRect(R, 0, 0, Width, Height);
    DrawEdge(DC, R, EdgeFlags, BorderFlags);
    MoveWindowOrg(DC, R.Left, R.Top);
    IntersectClipRect(DC, 0, 0, R.Right - R.Left, R.Bottom - R.Top);
  end;
  Perform(WM_ERASEBKGND, DC, 0);
  Perform(WM_PAINT, DC, 0);
  if FWinControls <> nil then
    for I := 0 to FWinControls.Count - 1 do
      with TWinControl(FWinControls[I]) do
        if Visible then PaintTo(DC, Left, Top);
  RestoreDC(DC, SaveIndex);
  Exclude(FControlState, csPaintCopy);
end;

JB
Hi ittay?
Why do you do it like this way? You just want to print non database reports, well Quickreport can do this too! I don't see why you think it's impossible with quickreport. You can use quickreport memo or quickreport richtext and I'm sure there are also other components on the net for solving your problem. You can even make your own quickreport component. No problems for preview or printing if you do it this way.
Explain me when I'm wrong.

You can even use Word for creating your reports if that isn't a problem for you.
Avatar of ittay

ASKER

to ZifNab:
after experimenting with the evaluation version a bit i found that merly having one of the quickreport components on my project (WITHOUT a TTable or TQuery etc) makes my program 'Databased aware' which means that if i try to install it on a different computer i can no longer just copy the exe files but i need to install all of delphi's database dlls. which means it"
  a. makes the installation more complex
  b. makes the program more demanding in disk space and memory
and don't forget i still have to manipulate the components for a porpose they weren't ment for (write some code for the OnNeedData event (i need to print tables)) maybe this will cause problems to...

so this is not the solution for me (maybe if the program were free, but at $100 ...)

thanks anyway
ittay

Ok, I see. Why not sending it directly to a word-document?
I see, maybe users don't have word. Tried Lineprnt and ppreview?
Avatar of ittay

ASKER

to zifnab:
both of the components you suggested are for delphi 2.0. i have to use delphi 1.0....
thanks,
ittay


Avatar of ittay

ASKER

to ZifNab:
ok, the ryprev unit is pretty much what i needed (with small adjustments)
if you want you can 'answer' the question so you'll get the points.
ASKER CERTIFIED SOLUTION
Avatar of ZifNab
ZifNab

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial