打印panel中的内容(包括image、memo),一页中含有多幅图片时,有时打印出来最后一幅图片会空白。我的打印部分代码如下,十万火急,请大侠指导。SetPrinter(nil);
printer.CleanupInstance;
printer.Title:=trim(form1.Caption);
printer.BeginDoc;
SetMapMode(printer.Canvas.Handle,MM_ANISOTROPIC);
SetWindowExtEx(printer.Canvas.Handle,PanelRep.Width,PanelRep.Height,nil); //PanelRep是一个panel,里面包括数个image、memo
SetViewportExtEx(printer.Canvas.Handle,printer.PageWidth,printer.PageHeight,nil);
panelRep.PaintTo(printer.Canvas,0,0);
printer.EndDoc;在win2000、xp下均出现过图片漏打,打印机包括HP 1600、2600彩激。新注册,积分少,但我会非常感谢的。

解决方案 »

  1.   

    var
      bit: TBitmap;
    begin
      SetPrinter(nil);
      printer.CleanupInstance;
      printer.Title := trim(form1.Caption);
      printer.BeginDoc;
      SetMapMode(printer.Canvas.Handle, MM_ANISOTROPIC);
      SetWindowExtEx(printer.Canvas.Handle, PanelRep.Width, PanelRep.Height, nil); //PanelRep是一个panel,里面包括数个image、memo
      SetViewportExtEx(printer.Canvas.Handle, printer.PageWidth, printer.PageHeight, nil);
      ///***
      bit := TBitmap.Create;
      try
        bit.PixelFormat := pf24bit;
        bit.Transparent := True;
        bit.Width := PanelRep.Width;
        bit.Height := PanelRep.Height;
        panelRep.PaintTo(bit.Canvas, 0, 0);
        Printer.Canvas.Draw(0, 0, bit);
      finally
        bit.Free;
      end;
      ///***
      printer.EndDoc;
    end;
    试试吧
      

  2.   

    用blazingfire的方法,用镜像打印机,比例失调,改用Printer.Canvas.StrechDraw绘图,在镜像打印机上正常,但是连接上激打打出来的是空白页,说不出什么原因来。请大侠赐教。
      

  3.   

    bit.Transparent := True;///去掉试试
      

  4.   

    试过了,有没有bit.Transparent := True没关系。
    在Printer.Canvas.Draw(0, 0, bit);插入一个定时器,定时1秒,然后EndDoc。打印成功。
    看来Printer.Canvas.Draw的优先级比较低,或则没有结束绘图就返回句柄,才打出空白页。
    但是blazingfire的方法打印出来的分辨率太低了。
    我还是仍旧用原来的方法打印,panelRep.PaintTo(printer.Canvas,0,0)和printer.EndDoc之间插入一个定时器试试看,如果问题解决,会回来报告的。
      

  5.   

    unit PPanel;interfaceuses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
      ExtCtrls, Printers, StdCtrls, DBCtrls, Mask, ComCtrls, Grids, DBGrids,
      Chart;type
      TPPanel = class(TPanel)
      private
        { Private declarations }
        SX,SY:Real;
        FShowBorder:Boolean;    FXOffset:Integer;
        FYOffset:Integer;    PreviewForm:TForm;
      protected
        { Protected declarations }
      public
        { Public declarations }
        Constructor Create(AOwner:TComponent); Override;
        Procedure PrintToCanvas(ACanvas:TCanvas);    Procedure WhenKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
        Procedure WhenFormPaint(Sender: TObject);
        Procedure WhenFormClose(Sender: TObject; var Action: TCloseAction);
      published
        { Published declarations }
        Function  Print(Preview:Boolean):Boolean;
        Procedure About;    Property ShowBorder:Boolean Read FShowBorder Write FShowBorder;
        Property XOffset:Integer Read FXOffset Write FXOffset;
        Property YOffset:Integer Read FYOffset Write FYOffset;
      end;procedure Register;implementation//注册组件
    procedure Register;
    begin
      RegisterComponents('Standard', [TPPanel]);
    end;Constructor TPPanel.Create(AOwner:TComponent);
    Begin
         Inherited;     FXOffset:=0;
         FYOffset:=0;
    End;//关于组件
    Procedure TPPanel.About;
    Begin
         Application.MessageBox('PPanel 作者:彭富章 2000.03','关于 PPanel',MB_OK+MB_ICONINFORMATION);
    End;//打印预览窗口键盘按下
    Procedure TPPanel.WhenKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    Begin
         If Key=VK_Return Then
         Begin
              Self.Print(False);
              If Sender Is TForm Then
                 TForm(Sender).ModalResult:=mrOK;
         End
         Else If Key=VK_ESCAPE Then
              PreViewForm.Close;
    End;//窗口刷新
    Procedure TPPanel.WhenFormPaint(Sender: TObject);
    Begin
         PrintToCanvas(PreviewForm.Canvas);
    End;//窗口关闭
    Procedure TPPanel.WhenFormClose(Sender: TObject; var Action: TCloseAction);
    Begin
         Action:=caFree;
    End;//打印
    Function TPPanel.Print(Preview:Boolean):Boolean;
    Var SS:TStringList;
    Begin
         If FileExists(ExtractFilePath(Application.ExeName)+'PRINT.INI') Then
         Begin
              SS:=TStringList.Create;
              SS.LoadFromFile(ExtractFilePath(Application.ExeName)+'PRINT.INI');          Try
                 If SS.Count>0 Then FXOffset:=StrToInt(SS.Strings[0]);
                 If SS.Count>1 Then FYOffset:=StrToInt(SS.Strings[1]);
              Except
              End;          SS.Clear;
              SS.Free;
         End;     Result:=False;
         If Preview Then
         Begin
              SX:=1.0;
              SY:=1.0;          PreViewForm:=TForm.Create(Application);
              PreViewForm.Caption:='打印预览 按[Enter]打印 按[Esc] 关闭';
              PreViewForm.BorderStyle:=bsDialog;
              PreViewForm.ClientWidth:=self.Width;
              PreViewForm.ClientHeight:=self.Height;
              PreViewForm.Color:=clWhite;
              PreviewForm.Position:=poScreenCenter;          PreviewForm.OnKeyDown:=WhenKeyDown;
              PreviewForm.OnPaint:=WhenFormPaint;
              PreviewForm.OnClose:=WhenFormClose;          If PreViewForm.ShowModal=mrOK Then
                 Result:=True;
         End
         Else
         Begin
              SX:=GetDeviceCaps(Printer.Handle,logPixelsX)/Screen.PixelsPerInch;
              SY:=GetDeviceCaps(Printer.Handle,logPixelsY)/Screen.PixelsPerInch;          Printer.BeginDoc;
              Printer.Title:='Doc printed by PrintPanel '+FormatDateTime('YYYY-MM-DD HH:MM:SS',Now);
              PrintToCanvas(Printer.Canvas);
              Printer.EndDoc;          Result:=True;
         End;
    End;
      

  6.   

    //绘制到指定画布
    Procedure TPPanel.PrintToCanvas(ACanvas:TCanvas);
    Var NowPage:Integer;
        I,N:Integer;
        AObj:TControl;
        ARect:TRect;
        PX,PY:Integer;
        Stemp:String;    WidthArray:Array[1..24] of Integer;
        ValueArray:Array[1..24] Of String;
        ColumnCount,X,Y,NowX,NowY:Integer;    NowRow:Integer;
    Begin
         NowPage:=1;     Try
         ACanvas.Lock;     With ACanvas Do
         For I:=0 To ControlCount-1 Do
         If Controls[I].Visible Then
         Begin
              AObj:=Controls[I];
              ARect:=AObj.BoundsRect;          ARect.Left:=ARect.Left+FXOffset;
              ARect.Top:=ARect.Top+FYOffset;
              ARect.Right:=ARect.Right+FXOffset;
              ARect.Bottom:=ARect.Bottom+FYOffset;          PX:=Round((ARect.Left+4)*SX);
              PY:=Round((ARect.Top+2)*SY);          ARect.Left:=Round(ARect.Left*SX);
              ARect.Top:=Round(ARect.Top*SY);
              ARect.Right:=Round(ARect.Right*SX);
              ARect.Bottom:=Round(ARect.Bottom*SY);          Font:=self.Font;          If (FShowBorder ) Then //OR (AObj Is TStringGrid)
              If ((AObj Is TEdit) OR (AObj Is TDBEdit) OR (AObj Is TMaskEdit) OR (AObj Is TDateTimePicker) OR (AObj Is TComboBox)
              OR (AObj Is TDbComboBox) OR (AObj Is TMemo) OR (AObj Is TDBmemo) OR (AObj Is TDBGrid) OR (AObj Is TStringGrid)) Then
              Begin
                   Pen.Width:=1;
                   MoveTo(ARect.Left,ARect.Top);
                   LineTo(ARect.Right,ARect.Top);
                   LineTo(ARect.Right,ARect.Bottom);
                   LineTo(ARect.Left,ARect.Bottom);
                   LineTo(ARect.Left,ARect.Top);
              End;          If AObj Is TLabel Then
              Begin
                   Stemp:=Uppercase(TLabel(AObj).Caption);
                   Font:=TLabel(AObj).Font;               If Stemp='%UP%' Then
                   Begin
                        If NowPage>1 Then
                           TextOut(ARect.Left,ARect.Top,'接上页');
                   End
                   Else If Stemp='%DOWN%' Then
                        TextOut(ARect.Left,ARect.Top,'接下页')
                   Else If Stemp='%PAGE%' Then
                        TextOut(ARect.Left,ARect.Top,'第 '+IntToStr(NowPage)+' 页')
                   Else If Stemp='%DATE%' Then
                        TextOut(ARect.Left,ARect.Top,FormatDateTime('YYYY-MM-DD',Now))
                   Else If Stemp='%TIME%' Then
                        TextOut(ARect.Left,ARect.Top,FormatDateTime('HH:MM:SS',Now))
                   Else If Stemp='%YYYY%' Then
                        TextOut(ARect.Left,ARect.Top,FormatDateTime('YYYY',Date))
                   Else If Stemp='%MM%' Then
                        TextOut(ARect.Left,ARect.Top,FormatDateTime('MM',Date))
                   Else If Stemp='%DD%' Then
                        TextOut(ARect.Left,ARect.Top,FormatDateTime('DD',Date))
                   Else
                       TextOut(ARect.Left,ARect.Top,TLabel(AObj).Caption);
              End
              Else If AObj Is TDBText Then
              Begin
                   Try
                      If Not TDBText(AObj).DataSource.DataSet.Active Then Continue;                  Font:=TDBText(AObj).Font;
                      TextOut(ARect.Left,ARect.Top,TDBText(AObj).Field.DisplayText);
                   Except
                   End;
              End
              Else If AObj Is TEdit Then
              Begin
                   Font:=TEdit(AObj).Font;
                   TextOut(PX,PY,TEdit(AObj).Text);
              End
              Else If AObj Is TDBEdit Then
              Begin
                   Try
                      If Not TDBEdit(AObj).DataSource.DataSet.Active Then Continue;                  Font:=TDBEdit(AObj).Font;
                      TextOut(PX,PY,TDBEdit(AObj).Field.DisplayText);
                   Except
                   End;
              End
              Else If AObj Is TMaskEdit Then
              Begin
                   Font:=TMaskEdit(AObj).Font;
                   TextOut(PX,PY,TMaskEdit(AObj).Text);
              End
              Else If AObj Is TDateTimePicker Then
              Begin
                   Stemp:='';
                   Font:=TDateTimePicker(AObj).Font;
                   If TDateTimePicker(AObj).ShowCheckBox Then
                   Begin
                        If TDateTimePicker(AObj).Checked Then
                           Stemp:='■'
                        Else
                            Stemp:='□';
                   End;               If TDateTimePicker(AObj).Kind=dtkDate Then
                      Stemp:=Stemp+FormatDateTime('YYYY-MM-DD',TDateTimePicker(AObj).Date)
                   Else
                       Stemp:=Stemp+FormatDateTime('HH:MM:SS',TDateTimePicker(AObj).Time);               TextOut(PX,PY,Stemp);
              End
              Else If AObj Is TBevel Then
              Begin
                   If TBevel(AObj).Shape=bsBottomLine Then
                   Begin
                        MoveTo(ARect.Left,ARect.Bottom);
                        LineTo(ARect.Right,ARect.Bottom);
                   End
                   Else If TBevel(Aobj).Shape=bsTopLine Then
                   Begin
                        MoveTo(ARect.Left,ARect.Top);
                        LineTo(ARect.Right,ARect.Top);
                   End
                   Else If TBevel(AObj).Shape=bsLeftLine Then
                   Begin
                        MoveTo(ARect.Left,ARect.Top);
                        LineTo(ARect.Left,ARect.Bottom);
                   End
                   Else If TBevel(AObj).Shape=bsRightLine Then
                   Begin
                        MoveTo(ARect.Right,ARect.Top);
                        LineTo(ARect.Right,ARect.Bottom);
                   End
                   Else If TBevel(AObj).Shape=bsBox Then
                   Begin
                        MoveTo(ARect.Left,ARect.Top);
                        LineTo(ARect.Right,ARect.Bottom);
                   End
                   Else
                   Begin
                        MoveTo(ARect.Left,ARect.Top);
                        LineTo(ARect.Right,ARect.Top);
                        LineTo(ARect.Right,ARect.Bottom);
                        LineTo(ARect.Left,ARect.Bottom);
                        LineTo(ARect.Left,ARect.Top);
                   End;
              End
              Else If AObj Is TComboBox Then
              Begin
                   Font:=TComboBox(AObj).Font;
                   TextOut(PX,PY,TComboBox(AObj).Text);
              End
              Else If AObj Is TDBComboBox Then
              Begin
                   If Not TDBComboBox(AObj).DataSource.DataSet.Active Then Continue;               Font:=TDBComboBox(AObj).Font;
                   TextOut(PX,PY,TDBComboBox(AObj).Field.AsString);
              End
              Else If AObj Is TCheckBox Then
              Begin
                   Font:=TCheckBox(AObj).Font;
                   If TCheckBox(AObj).Checked Then
                      TextOut(PX,PY,'■'+TCheckBox(AObj).Caption)
                   Else
                       TextOut(PX,PY,'□'+TCheckBox(AObj).Caption);
              End
      

  7.   

              Else If AObj Is TDBCheckBox Then
              Begin
                   If Not TDBCheckBox(AObj).DataSource.DataSet.Active Then Continue;               Font:=TDBCheckBox(AObj).Font;
                   If TDBCheckBox(AObj).Checked Then
                      TextOut(PX,PY,'■'+TDBCheckBox(AObj).Caption)
                   Else
                       TextOut(PX,PY,'□'+TDBCheckBox(AObj).Caption);
              End
              Else If AObj Is TRadioButton Then
              Begin
                   Font:=TRadioButton(AObj).Font;
                   If TRadioButton(AObj).Checked Then
                      TextOut(PX,PY,'●'+TRadioButton(AObj).Caption)
                   Else
                       TextOut(PX,PY,'◎'+TRadioButton(AObj).Caption);
              End
              Else If AObj Is TChart Then
              Begin
                   TChart(AObj).DrawToMetaCanvas(Canvas,ARect);
              End
              {Else If AObj Is TDBChart Then
              Begin
                   TDBChart(AObj).DrawToMetaCanvas(Canvas,ARect);
              End}
              Else If AObj Is TImage Then
              Begin
                   StretchDraw(ARect,TImage(AObj).Picture.Graphic);
              End
              Else If AObj Is TDBImage Then
              Begin
                   StretchDraw(ARect,TDBImage(AObj).Picture.Graphic);
              End
              Else If AObj Is TDBGrid Then
              Begin
                   Font:=TDBGrid(AObj).Font;               ColumnCount:=TDBGrid(AObj).Columns.Count;
                   If ColumnCount>24 Then ColumnCount:=24;               NowX:=ARect.Left;
                   For X:=0 To ColumnCount-1 Do
                   Begin
                        WidthArray[X+1]:=Round(TDBGrid(AObj).Columns[X].Width*SX);
                        ValueArray[X+1]:='';
                        NowX:=NowX+WidthArray[X+1];
                        If NowX>ARect.Right Then
                        Begin
                             ColumnCount:=X;
                             Break;
                        End;
                   End;               //draw DBGrid Title
                   NowX:=ARect.Left;
                   NowY:=ARect.Top;
                   For X:=0 To ColumnCount-1 Do
                   Begin
                        TextOut(NowX+4,NowY+2,TDBGrid(AObj).Columns[X].Field.DisplayLabel);
                        NowX:=NowX+WidthArray[X+1];
                   End;               NowY:=NowY+Round((ABS(TDBGrid(AObj).Font.Height)+4)*SY);
                   //NowY:=NowY+TDBGrid(AObj).DefaultRowHeight*SY;
                   Pen.Width:=2;
                   MoveTo(ARect.Left,NowY);
                   LineTo(ARect.Right,NowY);
                   Pen.Width:=1;               //draw records
                   TDBGrid(AObj).DataSource.DataSet.First;
                   While Not TDBGrid(AObj).DataSource.DataSet.Eof Do
                   Begin
                        //draw a record
                        NowX:=ARect.Left;
                        For X:=0 To ColumnCount-1 Do
                        Begin
                             If TDBGrid(AObj).Columns[X].Field.AsString<>ValueArray[X+1] Then
                             Begin
                                  ValueArray[X+1]:=TDBGrid(AObj).Columns[X].Field.AsString;
                                  TextOut(NowX+8,NowY+2,TDBGrid(AObj).Columns[X].Field.AsString);
                             End
                             Else
                                 TextOut(NowX+8,NowY+2,TDBGrid(AObj).Columns[X].Field.AsString);                         NowX:=NowX+WidthArray[X+1];
                        End;                    TDBGrid(AObj).DataSource.DataSet.Next;
                        NowY:=NowY+Round((ABS(TDBGrid(AObj).Font.Height)+4)*SY);
                        If (NowY+Round((ABS(TDBGrid(AObj).Font.Height)+4)*SY))>ARect.Bottom Then
                           Break;                    MoveTo(ARect.Left,NowY);
                        LineTo(ARect.Right,NowY);
                        NowY:=NowY+Round(4*SY);
                   End;               //draw lines
                   Pen.Width:=2;
                   NowX:=ARect.Left;
                   For X:=1 To ColumnCount-1 Do
                   Begin
                        NowX:=NowX+WidthArray[X];
                        MoveTo(NowX,ARect.Top);
                        LineTo(NowX,ARect.Bottom);
                   End;
                   Pen.Width:=1;
              End
              Else If AObj Is TStringGrid Then
              Begin
                   Font:=TStringGrid(AObj).Font;
                   Pen.Width:=0;               ColumnCount:=TStringGrid(AObj).ColCount;
                   If ColumnCount>24 Then ColumnCount:=24;               NowX:=ARect.Left;
                   NowY:=ARect.Top;
                   For X:=0 To ColumnCount-1 Do
                   Begin
                        WidthArray[X+1]:=Round(TStringGrid(AObj).ColWidths[X]*SX);
                        NowX:=NowX+WidthArray[X+1];
                        If NowX>ARect.Right Then
                        Begin
                             ColumnCount:=X;
                             Break;
                        End;
                   End;               //draw
                   NowRow:=0;
                   While NowRow<TStringGrid(AObj).RowCount Do
                   Begin
                        //draw a record
                        NowX:=ARect.Left;
                        For X:=0 To ColumnCount-1 Do
                        Begin
                             TextOut(NowX+8,NowY+Round(2*SY),TStringGrid(AObj).Cells[X,NowRow]);
                             NowX:=NowX+WidthArray[X+1];
                        End;                    Inc(NowRow);
                        //NowY:=NowY+Round((ABS(TStringGrid(AObj).Font.Height)+4)*SY);
                        NowY:=NowY+Round(TStringGrid(AObj).DefaultRowHeight*SY);
                        If (NowY+Round((ABS(TStringGrid(AObj).Font.Height)+4)*SY))>ARect.Bottom Then
                           Break;                    //MoveTo(ARect.Left,NowY);
                        //LineTo(ARect.Right,NowY);
                        NowY:=NowY+Round(4*SY);
                   End;               //draw lines
                   {Pen.Width:=2;
                   NowX:=ARect.Left;
                   For X:=1 To ColumnCount-1 Do
                   Begin
                        NowX:=NowX+WidthArray[X];
                        MoveTo(NowX,ARect.Top);
                        LineTo(NowX,ARect.Bottom);
                   End;
                   Pen.Width:=1;}
              End;
         End;
         Finally
           ACanvas.Unlock;
         End;
    End;end.
      

  8.   

    把上面3段存到文件中 PPanel.Pas 中 安装组件
    要打印的东西放在上面 调用 .Print 方法就可以打印了
      

  9.   

    AP兄的PPanel控件打印还是会丢图,我参考AP兄的控件StretchDraw(ARect,TImage(AObj).Picture.Graphic)代码,不用panel.PaintTo(printer.Canvas,0,0),改成手工将图片画进printer.Canvas,还是丢图。丢图的情况是打印1、2幅图片一般正常,打印4幅以上,随机出现其中某一幅漏打。即使同样内容多次打印,漏打的图片也不固定,可能是第3幅,也可能第4幅或第5幅。可能和Windows的打印接口有关系吧,代码应该没有错误。试者降低图片分辨率、色彩位数后(图元体积明显缩小),目前没出现漏打图片,只是打印效果差了点。先不结题,看看有没有即不降低打印质量,又可靠的解决办法。
      

  10.   

    问题基本解决了,我的代码没错,blazingfire和AP两位兄弟的代码也没错。原因是Printer.Canvas.Draw没有结束上一个控件(图或文本)的绘画就返回句柄,开始下一个控件的绘画了,如果是文本,体积小,不会出现问题,图片体积越大,出现的概率越高。所以,插入一个定时器,每幅图在Printer.Canvas.StretchDraw后面停止100ms,基本上不出现丢图。但是blazingfire兄的方法必然将文本内容也当成图片来打印,以600线分辨率生成的打印内容体积之大,会超过打印机的缓存。以屏幕分辨率生产打印内容,打印效果不敢恭维。Panel.PaintTo(printer.Canvas,0,0)对有些控件是不打印的,AP兄的PPanel控件增加了可以打印的控件的范围,只是有些控件只打印了文本,图形部分丢了。还是非常感谢两位兄弟的支持。