Solved

non databased reports

Posted on 1997-10-08
19
172 Views
Last Modified: 2010-04-04
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
0
Comment
Question by:ittay
  • 8
  • 5
  • 4
  • +2
19 Comments
 
LVL 22

Expert Comment

by:pivar
Comment Utility
Hi,

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

/pivar
0
 

Author Comment

by:ittay
Comment Utility
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)
0
 
LVL 5

Expert Comment

by:JimBob091197
Comment Utility
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
0
 

Author Comment

by:ittay
Comment Utility
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
0
 
LVL 5

Expert Comment

by:JimBob091197
Comment Utility
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
0
 
LVL 5

Expert Comment

by:JimBob091197
Comment Utility
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???
0
 
LVL 1

Expert Comment

by:AndersWP
Comment Utility
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
0
 

Author Comment

by:ittay
Comment Utility
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
0
 

Author Comment

by:ittay
Comment Utility
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.

0
Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 

Author Comment

by:ittay
Comment Utility
Adjusted points to 180
0
 
LVL 5

Expert Comment

by:JimBob091197
Comment Utility
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
0
 
LVL 8

Expert Comment

by:ZifNab
Comment Utility
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.

0
 
LVL 8

Expert Comment

by:ZifNab
Comment Utility
You can even use Word for creating your reports if that isn't a problem for you.
0
 

Author Comment

by:ittay
Comment Utility
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

0
 
LVL 8

Expert Comment

by:ZifNab
Comment Utility
Ok, I see. Why not sending it directly to a word-document?
I see, maybe users don't have word. Tried Lineprnt and ppreview?
0
 

Author Comment

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


0
 
LVL 8

Expert Comment

by:ZifNab
Comment Utility
0
 

Author Comment

by:ittay
Comment Utility
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.
0
 
LVL 8

Accepted Solution

by:
ZifNab earned 180 total points
Comment Utility
Glad I could help and that the question is resolved and do the question list is becoming one question smaller:

Here's the answer:

Ok, you have to use delphi 1.0
try this component :

http://carbohyd.siobc.ras.ru/torry/vcl/print/Ryprev.zip

Wish you good luck redesigning the component.
ZifNab;
0

Featured Post

Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

Join & Write a Comment

Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
This video discusses moving either the default database or any database to a new volume.
When you create an app prototype with Adobe XD, you can insert system screens -- sharing or Control Center, for example -- with just a few clicks. This video shows you how. You can take the full course on Experts Exchange at http://bit.ly/XDcourse.

772 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

10 Experts available now in Live!

Get 1:1 Help Now