• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 258
  • Last Modified:

Printer handles

I'm trying to use the Windows API StrechBlt to write the canvas from an Tpanel to the Printer canvas. However the result on the printed paper is the Windows background. I guess that the handle for the Tpanels canvas isn't valid for printing. My question is, how can I perform this copy of data from one canvas (TPanel.Canvas) to the Printer canvas (TPrinter.canvas)?
0
Probie
Asked:
Probie
  • 5
  • 2
  • 2
  • +3
1 Solution
 
intheCommented:
Hi,
this should print the entire panel and any components etc that are on it:


unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls,Printers, ExtCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Panel1: TPanel;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}
procedure PrintBitmap(Bitmap: TBitmap; printrect: TRect);
var
  Info: PBitmapInfo;
  InfoSize: DWORD;
  Image: Pointer;
  ImageSize: DWORD;
begin
  with Bitmap do
  begin
    GetDIBSizes(Handle, InfoSize, ImageSize);
    Info := AllocMem(InfoSize);
    try
      Image := AllocMem(ImageSize);
      try
        GetDIB(Handle, Palette, Info^, Image^);
        with Info^.bmiHeader, printrect do
          StretchDIBits(Printer.Canvas.Handle, Left, Top, Right-Left,             Bottom-Top, 0, 0, biWidth, biHeight, Image, Info^,
            DIB_RGB_COLORS, SRCCOPY);
      finally
        FreeMem(Image, ImageSize);
      end;
    finally
      FreeMem(Info, InfoSize);
    end;
  end;
end;


procedure TForm1.Button1Click(Sender: TObject);
  var
    Bitmap      :   TBitmap;
    FromLeft,
    FromTop,
    PrintedWidth,
    PrintedHeight : Integer;
begin
  Printer.BeginDoc;
  Try
    Bitmap := TBitmap.Create;
    Try
      Bitmap.Width  := Panel1.Width;
      Bitmap.Height := Panel1.Height;
      Bitmap.PixelFormat := pf24bit;
      Bitmap.Canvas.CopyRect(Rect(0,0, Bitmap.Width,Bitmap.Height),
                          Form1.Canvas,Rect(Panel1.Left, Panel1.Top,
                                  Panel1.Left + Panel1.Width-1,
                                  Panel1.Top  + Panel1.Height-1) );
     PrintedWidth  := MulDiv(Printer.PageWidth, 80,100);
     PrintedHeight := MulDiv(PrintedWidth, Bitmap.Height, Bitmap.Width);
     FromLeft      := MulDiv(Printer.PageWidth, 10,100);
     FromTop      := MulDiv(Printer.PageHeight,10,100);
     PrintBitmap(Bitmap,Rect(FromLeft, FromTop,FromLeft + PrintedWidth,FromTop  + PrintedHeight));
    Finally
      Bitmap.Free
    End;
  Finally
    Printer.EndDoc
  End;
 end;
end.



Regards Barry
0
 
ProbieAuthor Commented:
I would like to know why I get the Windows background printed and how I can read from the TPanel.Canvas direct
and write it to the printer canvas using the Windows API StreachBlt.

(I can't copy direct from the Form.canvas as you are doing in the example)
0
 
DrDelphiCommented:
Where do you see a CANVAS property for Tpanel? The best you can do is make a call to the GetDC API passing the Hwnd of TPanel. there is no canvas property.

0
Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
intheCommented:
i suppose a panel more or less is a canvas ;-)

what is on the panel that you want to print?
0
 
MadshiCommented:
I agree with DrDelphi here...
0
 
hubdogCommented:
begin
  printer.begindoc;
  printer.Canvas.Brush.Color:=clwhite;
  stretchblt(printer.Canvas.Handle,100,100,
             printer.pagewidth-100,printer.pageheight-100,
             GetDc(panel1.handle),0,0,
             panel1.width,panel1.height,srccopy);
  printer.enddoc;
end;
i test it ,with background white

good luck

hubdog
0
 
ProbieAuthor Commented:
I'm not using a Tpanel only. I have made a class: TModule = class(TPanel) in which I have made the TCanvas property public. I can read and write to it but the StretchBlt API doesn't seem to like the handle of the Tmodule (Tpanel) since I get the Windows background canvas printed instead of the Tpanels.
0
 
hubdogCommented:
sorry,i was wrong
0
 
ProbieAuthor Commented:
I'm not using a Tpanel only. I have made a class: TModule = class(TPanel) in which I have made the TCanvas property public. I can read and write to it but the StretchBlt API doesn't seem to like the handle of the Tmodule (Tpanel) since I get the Windows background canvas printed instead of the Tpanels.
0
 
MadshiCommented:
You used TModule.canvas.handle, not TModule.handle, right?
0
 
ProbieAuthor Commented:
Well, I have used em both and I have no problem in printing a visible TPanel. My problem is that I want to print multiple TPanels on one paper. In order to do this I made a loop simply printing each panel. However, only the panel that was visible when I pressed the print button is printed correct. All the others seems to take the Windows background as pixel data.

I can solve this problems by calling the TPanel.Show before I do the StreatchBlt to the Printer.canvas but that is a nasty solution and I wish that I could print all my panels without having to first call their .show metod.

(I have tried to use repaint, refresh, piantWindow, but they did not fix it, it seems like the panel needs to be visible in order to get the canvas of it)





0
 
brunoheCommented:
This is a very serious problem and not very easy to solve. I had to do nearly the same, but the only solution for me was to provide a second draw method in my component which scales and paints my component to a printercanvas.

For you using a panel; there are problems in windows with the bit-block transfers using Stretchblt, Bitblt etc. I dont know exactly if they are only with windows 9x, but there are.

Your problem with the background-prints MAY have the same reason, but not for sure.

Another reason may be, that you panel is not painted as well. The panel paints only if it is somewhere visible on the screen. You can evaluate this by setting a breakpoint in you WM_PAINT of the panel und use the Cliprect to determine if theres an area to be painted on the panels surface.
0
 
brunoheCommented:
p.s.: I just read your Comment again; Your Prob is that the panel is not visible a the time you print it. Windows does not redraw anything not visible to the screen and TCanvas.Canvas is affected by this.
Normally forced by InvalidateRect.

That's the way it works. Perhaps you can manage your problem when you show the panel and copy the canvas to a TBitmap-instance.

0
 
ProbieAuthor Commented:
Thank's for the help, it turned out to depend on if the Panel was visible or not. I would like to give brunohe and hubdog 100p each but since it dosen't work that way and that I don't have any points left I'll give the points to hubdog as a thanks for the example.

/Probie
0

Featured Post

The 14th Annual Expert Award Winners

The results are in! Meet the top members of our 2017 Expert Awards. Congratulations to all who qualified!

  • 5
  • 2
  • 2
  • +3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now