⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 printer.htm

📁 对于学习很有帮助
💻 HTM
📖 第 1 页 / 共 3 页
字号:
<!-- This document was created with HomeSite v2.5 -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">

<HTML>
<HEAD>
	<TITLE>UDDF - Printer</TITLE>
	<META NAME="Description" CONTENT="Printer section of the Delphi Developers FAQ" >
	<META NAME="KeyWords" CONTENT="" >

</HEAD>

<BODY bgcolor="#FFFFFF">
<CENTER>
<IMG SRC="../images/uddf.jpg"> </CENTER>
<HR SIZE="6" color="#00FF00">


<CENTER><FONT SIZE="7" FACE="Arial Black" COLOR="RED">Printer</FONT></CENTER>
<P><H1><A NAME="printer0">Help on Printer Control Codes</P></A></H1>
<P><I>From: dblock@vdn.com (David Block)</I></P>

<PRE>Vincent Lim &lt;kaneda@singnet.com.sg&gt; wrote:

How do I send Printer Control Codes to the printer without having them
translated into unprintable characters?
Not sure if it is Windows API or Delphi is the culprit.
When I write the printer control codes, they are just printed as
unprintable characters rather than being interpreted by the printer.
</PRE>

You need to use the Passthrough printer Escape function to send data
directly to the printer. If you're using WriteLn, then it won't work.
Here's some code to get you started:
<P>
<HR><PRE>unit Passthru;

interface

uses printers, WinProcs, WinTypes, SysUtils;

Procedure       PrintTest;

implementation

Type
        TPassThroughData = Record
                nLen : Integer;
                Data : Array[0..255] of byte;
        end;

Procedure DirectPrint(s : String);
var
        PTBlock : TPassThroughData;
Begin
        PTBlock.nLen := Length(s);
        StrPCopy(@PTBlock.Data,s);
        Escape(printer.handle, PASSTHROUGH,0,@PTBlock,nil);
End;



Procedure PrintTest;
Begin
        Printer.BeginDoc;
        DirectPrint(CHR(27)+'&amp;l1O'+'Hello, World!');
        Printer.EndDoc;
End;


end.
</PRE><HR>

<P><H1><A NAME="printer1">How to get Paper Source?</P></A></H1>
<P><I> 'Joe C. Hecht' &lt;jhecht@wpo.borland.com&gt;</I></P>


<P>Below are some code snippets to change the printer settings. Wherever the changes are made, you could instead examine the printer settings. 
See the documentation for  ExtDeviceMode and the TDEVMODE structure as well the printer escape GETSETPAPERBINS and GetDeviceCaps().</P>

*********************************************
<P>One way to change printer settings at the start of a print job is to change the printers devicemode.</P>

<P>Example:</P>

<HR><PRE>var
Device : array[0..255] of char;
Driver : array[0..255] of char;
Port   : array[0..255] of char;
hDMode : THandle;
PDMode : PDEVMODE;
begin
  Printer.PrinterIndex := Printer.PrinterIndex;
  Printer.GetPrinter(Device, Driver, Port, hDMode);
  if hDMode &lt;&gt; 0 then begin
    pDMode := GlobalLock(hDMode);
    if pDMode &lt;&gt; nil then begin
      pDMode^.dmFields := pDMode^.dmFields or DM_COPIES;
      pDMode^.dmCopies := 5;
      GlobalUnlock(hDMode);
    end;
    GlobalFree(hDMode);
  end;
  Printer.PrinterIndex := Printer.PrinterIndex;
  Printer.BeginDoc;
  Printer.Canvas.TextOut(100,100, 'Test 1');
  Printer.EndDoc;
</PRE><HR>

<P>Another way is to change TPrinter.
This will enable you to change settings in mid job. 
You must make the change &gt;&gt;&gt;between&lt;&lt;&lt; pages.</P>

<P>To do this:</P>

<P>Before every startpage() command in printers.pas in the Source\VCL directory add something like:</P>

<HR><PRE> DevMode.dmPaperSize:=DMPAPER_LEGAL
{any other devicemode settings go here}
 Windows.ResetDc(dc,Devmode^);
</PRE><HR>

<P>This will reset the pagesize. you can look up DEVMODE in the help to find other paper sizes.</P>

<P>You will need to rebuild the vcl source for this to work, by adding the path to the VCL source directory to the beginning of the library path s
tatement under tools..options.. library...libaray path. Quit Delphi then do a build all.</P>

<P><B>Another quick note...</B></P>

<P>When changing printers, be aware that fontsizes may not always scale properly. To ensure proper scaling set the PixelsPerInch property of the font.</P>

<P>Here are two examples:</P>

<HR><PRE>uses Printers;

var
  MyFile: TextFile;
begin
  AssignPrn(MyFile);
  Rewrite(MyFile);

  Printer.Canvas.Font.Name := 'Courier New';
  Printer.Canvas.Font.Style := [fsBold];
  Printer.Canvas.Font.PixelsPerInch:=
    GetDeviceCaps(Printer.Canvas.Handle, LOGPIXELSY);

  Writeln(MyFile, 'Print this text');

  System.CloseFile(MyFile);
end;
</PRE><HR>

<HR><PRE>uses Printers;

begin
  Printer.BeginDoc;
  Printer.Canvas.Font.Name := 'Courier New';
  Printer.Canvas.Font.Style := [fsBold];

  Printer.Canvas.Font.PixelsPerInch:=
    GetDeviceCaps(Printer.Canvas.Handle, LOGPIXELSY);

  Printer.Canvas.Textout(10, 10, 'Print this text');

  Printer.EndDoc;
end;
</PRE><HR>

<P><H1><A NAME="printer2">How to Print VERTICAL oriented text in Delphi</P></A></H1>
<P><I>From: "Peter Szymiczek" &lt;szymicpe@bmw.com.au&gt;</I></P>

<HR><PRE>procedure AngleTextOut(CV: TCanvas; const sText: String; x, y, angle:integer);
var
  LogFont: TLogFont;
  SaveFont: TFont;
begin
  SaveFont := TFont.Create;
  SaveFont.Assign(CV.Font);
  GetObject(SaveFont.Handle, sizeof(TLogFont), @LogFont);
  with LogFont do
    begin
      lfEscapement := angle *10;
      lfPitchAndFamily := FIXED_PITCH or FF_DONTCARE;
    end; {with}
  CV.Font.Handle := CreateFontIndirect(LogFont);
  SetBkMode(CV.Handle, TRANSPARENT);
  CV.TextOut(x, y, sText);
  CV.Font.Assign(SaveFont);
  SaveFont.Free;
end;
</PRE><HR>


<P><H1><A NAME="printer3">Help - Printing sideways text...</P></A></H1>
<P><I>From: Jukka Palom&auml;ki &lt;jukpalom@utu.fi&gt;</I></P>

<P>This is how I have solved the problem:</P>

<HR><PRE>procedure TextOutVertical(var bitmap: TBitmap; x, y: Integer; s: String);
var b1, b2: TBitmap;
    i, j: Integer;
begin
  with bitmap.Canvas do
  begin
    b1 := TBitmap.Create;
    b1.Canvas.Font := lpYhFont;
    b1.Width  := TextWidth(s) + 1;
    b1.Height := TextHeight(s) + 1;
    b1.Canvas.TextOut(1, 1, s);

    b2 := TPackedBitmap.Create;
    b2.Width  := TextHeight(s);
    b2.Height := TextWidth(s);
    for i := 0 to b1.Width - 1 do
        for j := 0 to b1.Height do
            b2.Canvas.Pixels[j, b2.Height + 1 - i] := b1.Canvas.Pixels[i, j];
    Draw(x, y, b2);
    b1.Free;
    b2.Free;
  end
end;
</PRE><HR>

<P><H1><A NAME="printer4">How to print a bitmap?</P></A></H1>
<P>Use the following code.  Remember to include the Printers unit in the uses clause :</P>

<P>Lines followed by // ** are essential.  The others are to get the scaling correct otherwise you end up with extremely small images. 
 Printer resolutions are higher than your screen resolution.</P>

<HR><PRE>procedure TForm1.Button1Click(Sender: TObject);
var
  ScaleX, ScaleY: Integer;
  R: TRect;
begin
  Printer.BeginDoc;  // **
  with Printer do
  try
    ScaleX := GetDeviceCaps(Handle, logPixelsX) div PixelsPerInch;
    ScaleY := GetDeviceCaps(Handle, logPixelsY) div PixelsPerInch;
    R := Rect(0, 0, Image1.Picture.Width * ScaleX,
      Image1.Picture.Height * ScaleY);
    Canvas.StretchDraw(R, Image1.Picture.Graphic);  // **
  finally
    EndDoc;  // **
  end;
end;
</PRE><HR>

<P><H1><A NAME="printer5">Hack: tired of ReportSmith?  Wish you had wysiwyg reports?</P></A></H1>
<P><I>From: "James D. Rofkar" &lt;jim_rofkar%lotusnotes1@instinet.com></I></P>

<P>For those of you who are sick and tired of mucking around with ReportSmith, only to find limitations, drawbacks, etc.  
And have grown tired of trying to find that perfect WYSIWYG report generator.</P>

<P>Well...</P>

<P>Chances are you've got a good one already.  It's called MS-Word! That's right!  Use Word for report generation.  
It's actually quite easy with OLE Automation.  I know that word (OLE) scares some of you, but check-out this code:</P>

<HR><PRE>  var
     Word: Variant;
  begin
     Word := CreateOleObject('Word.Basic');
     with Word do
        begin {Pure WordBASIC commands follow...}
        FileNew('Normal');
        Insert('This is the first line'#13);
        Insert('This is the second line'#13);
        FileSaveAs('c:\temp\test.txt', 3);
        end;
  end;
</PRE><HR>
<P>Simple, isn't it?  If you notice, there's no need for SendMessage(), or PostMessage(), or DDE, or Word's C-API, or some proprietary  
DOS-based batch programming that requires text files to be  written.  In fact, none of that junk!</P>

<P>Another benefit of OLE Automation is that it doesn't require the darned app to launch.  That's right!  Word does not show-up using this technique. 
 Instead, just the WordBASIC engine is used.  The speed improvements and lower memory footprint kick the livin' crap out of the techniques listed in the previous paragraph.</P>

<P>A wild side-benefit is that if you startup Word while your program is using OLE Automation, you can watch it work.  
Yup!  Word realizes that "documents" are opened and being editing, and hence, displays them like regular old Word documents.</P>

<P>Now all you need to do is generate a Word template with Bookmarks! Then, using the WordBASIC commands "EditBookmark .Goto" and "Insert",  you're ready to rock!</P>

<P>I've given-up on report generators.  They suck compared to Word's WYSIWYG output!</P>

<P>- Jim Rofkar.</P>

<P>P.S. - If you use this technique, try to incorporate my name somewhere in your source comments.  Thanks.  I'll return the favor if I use one of your cool hacks!</P>

<P><H1><A NAME="printer6">Dump a text file</P></A></H1>
<P><I>From: Chris Monson &lt;ckmonson@burgoyne.com></I></P>

<P>Use CreateFile to get a handle to LPT1</P>

<HR><PRE>  LPTHandle := CreateFile( 'LPT1',GENERIC_WRITE,
                 0, PSecurityAttributes(nil),
                 OPEN_EXISTING, FILE_FLAG_OVERLAPPED,
                 0);
</PRE><HR>

<P>Then use WriteFile to send a string of characters or use</P>

<HR><PRE>  While not
    TransmitCommChar( LPTHandle, CharToSend ) do
  Application.ProcessMessages;
</PRE><HR>

<P>It sends one raw character at a time to the parallel port.  It waits for
the recent character to get processed and then immediately sends a new
one.  I got it printing stuff pretty fast.</P>

<P><H1><A NAME="printer7">Printing a line at a time</P></A></H1>
<P><I>From:             Peter van Lonkhuyzen &lt;peterv@lin01.global.co.za></I></P>

<PRE>> I've tried to write a D1 or D2 program that will print only one line at a time to a printer (any type), exit the program but NOT eject the page, 
so that the next time I run the program and it prints a line, it prints on the very next line, etc.</PRE>

<P>According to M$ this is illegal as it "defeats the multitasking nature"  but I needed the same functionality.</P>

<P>I created the following derivative of the TPrinter object. It works perfectly on dotmatrix printers.</P>

<P>sample usage</P>

<HR><PRE>var Myprinter : TRawPrinter;
    oldprinter : TPrinter;
begin
 MyPrinter:=TRawPrinter.Create;
 oldprinter:=setprinter(MyPrinter);
 try
  if Printdialog1.execute then
  begin
    myprinter.startraw;
    myprinter.write('khsdhskhkshdksd');
    myprinter.writeln;
    myprinter.endraw;
  end
 finally
  setprinter(oldprinyter);
  myprinter.free;
 end
end;
</PRE><HR>

<P>Here is the code for the raw printer object.</P>

<HR><PRE>unit Rawprinter;

interface
uses printers,windows;

type TRawprinter =class(TPrinter)
                  public
                    dc2 : HDC;
                    procedure startraw;
                    procedure endraw;
                    procedure write(const s : string);
                    procedure writeln;
                  end;

implementation
uses sysutils,forms;

function AbortProc(Prn: HDC; Error: Integer): Bool; stdcall;
begin
  Application.ProcessMessages;
  Result := not Printer.Aborted;
end;

type
  TPrinterDevice = class
    Driver, Device, Port: String;
    constructor Create(ADriver, ADevice, APort: PChar);
    function IsEqual(ADriver, ADevice, APort: PChar): Boolean;
  end;

constructor TPrinterDevice.Create(ADriver, ADevice, APort: PChar);
begin
  inherited Create;
  Driver := ADriver;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -