การเขียนโปรแกรมสั่งงานเครื่องพิมพ์ เป็นเรื่องที่ตำราต่างๆ ไม่ค่อยจะได้กล่าวถึง ไม่ทราบว่าจะต้องการกั๊กหรืออย่างไร ด้านการเขียน โปรแกรมโหราศาสตร์ โดยเฉพาะ โหราศาสตร์ยูเรเนียน เคยพบว่าบางโปรแกรมก็ไม่ได้ใส่ฟังก์ชันด้านการพิมพ์ไว้ จะเป็นเพราะเน้นลูกเล่นตัวโปรแกรมในหน้าจอจนไม่เห็นความสำคัญ หรือไม่รู้เรื่องการสั่งพิมพ์จริงๆ ก็ไม่ทราบ หากเป็นโปรแกรมฟรี ก็พอเข้าใจได้ แต่ถ้าเป็นโปรแกรมที่ต้องซื้อแล้ว ถ้าพิมพ์อะไรไม่ได้จะรู้สึกว่าขาดสิ่งสำคัญไปมาก
ในการเขียนโปรแกรมด้วย Delphi นั้น จากหลักการ OOP (Object Oriented Programming) ได้ทำให้การสั่งวาดภาพด้วย Component ต่างๆ ในหน้าจอ กับการวาดภาพทางเครื่องพิมพ์สามารถทำได้ในลักษณะเดียวกัน ดังเช่นการสั่งวาดวงกลมขนาดเส้นผ่าศูนย์กลาง 600 Pixel ใน TImage อาจใช้คำสั่งว่า Image1.Canvas.Ellipse(0,0,600,600); เมื่อใช้คำสั่งวาดวงกลมในขนาด Pixel เดียวกันนี้ทางเครื่องพิมพ์ ก็ใช้คำสั่งว่า Printer.Canvas.Ellipse(0,0,600,600);
ปัญหามีอยู่ว่าจำนวน Pixel ในหน้าจอคอมพิวเตอร์มีจำกัดว่าในหน้ากระดาษที่พิมพ์ทางเครื่องพิมพ์มากนัก ตัวอย่างจากสถิติการชมเว็บไซต์ทั่วไปขณะนี้พบว่า user ส่วนใหญ่จะใช้ Resolution ที่ 1024X768 Pixel แต่ถ้าเป็นการพิมพ์ทางเครื่องพิมพ์ที่มีความละเอียดหลากหลาย ตั้งแต่ประมาณ 600 จุดต่อนิ้วขึ้นไป หรือเฉลี่ย 1200 จุดต่อนิ้ว ภาพที่เต็มหน้าจอ 1024 Pixel เมื่อออกทางเครื่องพิมพ์จะเหลือขนาดไม่ถึง 1 นิ้วเลย
หากนำเอาภาพที่สั่งวาดทางหน้าจอไป copy ออกทางเครื่องพิมพ์ให้ขยายใหญ่เต็มกระดาษตามสัดส่วนล่ะ จากที่ผมเคยใช้วิธีนี้กับภาพดวงในโปรแกรมรุ่นเก่า ผลปรากฏว่าขนาดเส้นต่างๆ ใหญ่ขึ้นตามไปด้วย ดูไม่สวยงาม ในโปรแกรมรุ่นหลังๆ ผมจึงใช้วิธีการสั่งวาดทางเครื่องพิมพ์โดยใช้คำสั่งเดียวกัน แต่กำหนดสัดส่วนของภาพใหม่หมด ดังเช่นในโปรแกรมตัวอย่างข้างล่าง โดยอิงกับขนาด จานคำนวณ ที่มีเส้นผ่าศูนย์กลาง 12 เซ็นติเมตร และการตรวจสอบว่าเครื่องพิมพ์ที่จะใช้งานมีขนาดความละเอียด (Resolution) เท่าไหร่ สำหรับคนที่ไม่ได้เรียนเน้นมาทางคำนวณอย่างผมก็เล่นเอาเหนื่อยกว่าจะกำหนดสัดส่วนที่ถูกใจได้ แต่ทำเสร็จแล้วก็คุ้มครับ ลองศึกษาจาก Source Code ข้างล่างนะครับ หรือ Download ได้ที่นี่ --> PrintDialDemo.zip (181.89 KB)
Source Code สำหรับสร้าง Form
object Form1: TForm1
Left = 345
Top = 126
BorderIcons = [biSystemMenu, biMinimize]
BorderStyle = bsSingle
Caption = 'ตัวอย่างการสั่งพิมพ์ด้วยคำสั่งวาดภาพ'
ClientHeight = 407
ClientWidth = 363
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
Position = poDesktopCenter
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object Image1: TImage
Left = 0
Top = 0
Width = 361
Height = 361
end
object BitBtn1: TBitBtn
Left = 280
Top = 368
Width = 75
Height = 25
TabOrder = 0
Kind = bkClose
end
object Button1: TButton
Left = 189
Top = 368
Width = 75
Height = 25
Caption = 'สั่งพิมพ์'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = [fsBold]
ParentFont = False
TabOrder = 1
OnClick = Button1Click
end
object PrintDialog1: TPrintDialog
Left = 128
Top = 368
end
end
Source Code ตัวโปรแกรม
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, Math, StdCtrls, Buttons, Printers;
type
TForm1 = class(TForm)
Image1: TImage;
BitBtn1: TBitBtn;
Button1: TButton;
PrintDialog1: TPrintDialog;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
ChartSize, ChartCenter, X1,X2,Y1,Y2 : Integer;
Index, SubIndex : Real;
PixelsInInchX: integer; { Stores Pixels per inch }
PixelsInInchY: integer;
PixelsInCentX: integer;
PixelsInCentY: integer;
PageW, PageH, CenterPageX, CenterPageY : Integer;
Function Normal360(x : Real):Real;
Procedure DrawDial360;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
Function TForm1.Normal360(x : Real):Real;
begin
Repeat
if X<0 then X := X+360;
if X>=360 then X := X-360;
until (X>=0)and(X<360);
Result := X;
end;
Procedure TForm1.DrawDial360;
Var I,E : Integer;
begin
With Image1.Canvas do begin
Pen.Color := RGB ( 0, 0, 85);
Image1.Canvas.Brush.Style := bsSolid;
Rectangle( 0, 0,ChartSize,ChartSize);
Pen.Color := RGB (255, 0,64);
Image1.Canvas.Brush.Style := bsClear;
Ellipse(ChartCenter-140, ChartCenter-140, ChartCenter+140, ChartCenter+140);
Pen.Color := ClPurple;
Ellipse(ChartCenter-120, ChartCenter-120, ChartCenter+120, ChartCenter+120);
Ellipse(ChartCenter-10, ChartCenter-10, ChartCenter+10, ChartCenter+10);
for I:=1 to 12 do begin // 12 Main Lines
SubIndex := Index+(I*30); Normal360(SubIndex);
X1 := ChartCenter-Trunc(140*Sin(SubIndex*pi/180));
Y1 := ChartCenter-Trunc(140*Cos(SubIndex*pi/180));
X2 := ChartCenter-Trunc(10*Sin(SubIndex*pi/180));
Y2 := ChartCenter-Trunc(10*Cos(SubIndex*pi/180));
Case I of
3 : Pen.Color := RGB(0,0,255); // First House
12 : Pen.Color := RGB(255,0,0); // Tenth House
else Pen.Color := ClPurple;
end;
Moveto(X1,Y1);
Lineto(X2,Y2);
if I in [3,6,9,12] then begin // Arrow on Square Point
X2 := ChartCenter-Trunc(120*Sin((SubIndex+5)*pi/180));
Y2 := ChartCenter-Trunc(120*Cos((SubIndex+5)*pi/180));
Moveto(X1,Y1); Lineto(X2,Y2);
X2 := ChartCenter-Trunc(120*Sin((SubIndex-5)*pi/180));
Y2 := ChartCenter-Trunc(120*Cos((SubIndex-5)*pi/180));
Moveto(X1,Y1); Lineto(X2,Y2);
end;
end;
Pen.Color := RGB(255,0,64);
for I:=0 to 3 do begin // Arrow at 4 of 45 Degree
SubIndex := Index+45+(I*90); Normal360(SubIndex);
X1 := ChartCenter-Trunc(140*Sin(SubIndex*pi/180));
Y1 := ChartCenter-Trunc(140*Cos(SubIndex*pi/180));
X2 := ChartCenter-Trunc(120*Sin(SubIndex*pi/180));
Y2 := ChartCenter-Trunc(120*Cos(SubIndex*pi/180));
Moveto(X1,Y1);
Lineto(X2,Y2);
X2 := ChartCenter-Trunc(120*Sin((SubIndex+2)*pi/180));
Y2 := ChartCenter-Trunc(120*Cos((SubIndex+2)*pi/180));
Moveto(X1,Y1); Lineto(X2,Y2);
X2 := ChartCenter-Trunc(120*Sin((SubIndex-2)*pi/180));
Y2 := ChartCenter-Trunc(120*Cos((SubIndex-2)*pi/180));
Moveto(X1,Y1); Lineto(X2,Y2);
end;
for I:=1 to 71 do // Every 5 Degree
if I in [6,9,12,18,24,27,30,36,42,45,48,54,60,63,66] then else
begin
SubIndex := Index+(I*5); Normal360(SubIndex);
if (I mod 3)=0 then E:=125 else E:=130;
X1 := ChartCenter-Trunc(140*Sin(SubIndex*pi/180));
Y1 := ChartCenter-Trunc(140*Cos(SubIndex*pi/180));
X2 := ChartCenter-Trunc(E*Sin(SubIndex*pi/180));
Y2 := ChartCenter-Trunc(E*Cos(SubIndex*pi/180));
Moveto(X1,Y1);
Lineto(X2,Y2);
end;
for I := 1 to 359 do // Mini Lines Every Degree
if (I mod 5) = 0 then else
begin
SubIndex := Index+I; Normal360(SubIndex);
X1 := ChartCenter-Trunc(140*Sin(SubIndex*pi/180));
Y1 := ChartCenter-Trunc(140*Cos(SubIndex*pi/180));
X2 := ChartCenter-Trunc(135*Sin(SubIndex*pi/180));
Y2 := ChartCenter-Trunc(135*Cos(SubIndex*pi/180));
Moveto(X1,Y1);
Lineto(X2,Y2);
end;
end; // With
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
ChartSize := Image1.Width;
ChartCenter := Round(ChartSize/2);
Index := 90;
DrawDial360;
end;
procedure TForm1.Button1Click(Sender: TObject);
Var I,E : Integer; EE, Index90, SubIndex90 : Real;
begin
if PrintDialog1.Execute then begin
PixelsInInchx := GetDeviceCaps(Printer.Handle, LOGPIXELSX); { Get Pixels per inch horizonally}
PixelsInInchY := GetDeviceCaps(Printer.Handle, LOGPIXELSY); { Get Pixels per inch vertically}
PixelsInCentX := Trunc(PixelsInInchx / 2.54);
PixelsInCentY := Trunc(PixelsInInchY / 2.54);
PageW := Printer.PageWidth;
PageH := Printer.PageHeight;
CenterPageX := PageW div 2;
CenterPageY := (PageH div 2)-Trunc(3.5*PixelsInCentY);
Try
Printer.BeginDoc;
Application.ProcessMessages; { Allow Drawing of abort box }
With Printer.Canvas do begin
Brush.Style := bsClear;
Font.Name := 'AngsanaUPC';
Font.Size := 16;
TextOut(PixelsInCentX, PixelsInCentY, 'Test Printing with Delphi');
if PixelsInInchX<300 then Pen.Width :=1 else Pen.Width := 3;
Pen.Color := RGB ( 0, 0, 85);
Ellipse(Trunc(CenterPagex-PixelsInCentx*0.3), Trunc(CenterPageY-PixelsInCentY*0.3),
Trunc(CenterPagex+PixelsInCentx*0.3), Trunc(CenterPageY+PixelsInCentY*0.3));
Ellipse(Trunc(CenterPagex-PixelsInCentx*6), Trunc(CenterPageY-PixelsInCentY*6),
Trunc(CenterPagex+PixelsInCentx*6), Trunc(CenterPageY+PixelsInCentY*6));
Ellipse(Trunc(CenterPagex-PixelsInCentx*5.0), Trunc(CenterPageY-PixelsInCentY*5.0),
Trunc(CenterPagex+PixelsInCentx*5.0), Trunc(CenterPageY+PixelsInCentY*5.0));
end; // with Printer
With Printer.Canvas do begin
for I:=1 to 12 do begin // 12 Main Lines
SubIndex := Index+(I*30); Normal360(SubIndex);
X1 := CenterPageX-Trunc(PixelsInCentX*6*Sin(SubIndex*pi/180));
Y1 := CenterPageY-Trunc(PixelsInCentY*6*Cos(SubIndex*pi/180));
X2 := CenterPageX-Trunc(PixelsInCentX*0.3*Sin(SubIndex*pi/180));
Y2 := CenterPageY-Trunc(PixelsInCentY*0.3*Cos(SubIndex*pi/180));
Case I of
3 : begin // First House
Pen.Color := RGB(0,0,255);
end;
12 : begin // Tenth House
Pen.Color := RGB(255,0,0);
end;
else Pen.Color := ClPurple;
end;
Moveto(X1,Y1);
Lineto(X2,Y2);
X2 := CenterPageX-Trunc(PixelsInCentX*4.0*Sin((SubIndex-15)*pi/180));
Y2 := CenterPageY-Trunc(PixelsInCentY*4.0*Cos((SubIndex-15)*pi/180));
X2 := X2-Trunc((PixelsInCentX*0.5)/(PixelsInCentX*12)*(CenterPageX+(PixelsInCentX*6)-X2));
Y2 := Y2-Trunc((PixelsInCentY*0.5)/(PixelsInCentY*12)*(CenterPageY+(PixelsInCentY*6)-Y2));
if I in [3,6,9,12] then begin // Arrow on Square Point
X2 := CenterPageX-Trunc(PixelsInCentX*5.0*Sin((SubIndex+2)*pi/180));
Y2 := CenterPageY-Trunc(PixelsInCentY*5.0*Cos((SubIndex+2)*pi/180));
Moveto(X1,Y1); Lineto(X2,Y2);
X2 := CenterPageX-Trunc(PixelsInCentX*5.0*Sin((SubIndex-2)*pi/180));
Y2 := CenterPageY-Trunc(PixelsInCentY*5.0*Cos((SubIndex-2)*pi/180));
Moveto(X1,Y1); Lineto(X2,Y2);
end;
end;
Pen.Color := RGB(255,0,64);
for I:=0 to 3 do begin // Arrow at 4 of 45 Degree
SubIndex := Index+45+(I*90); Normal360(SubIndex);
X1 := CenterPageX-Trunc(PixelsInCentX*6*Sin(SubIndex*pi/180));
Y1 := CenterPageY-Trunc(PixelsInCentY*6*Cos(SubIndex*pi/180));
X2 := CenterPageX-Trunc(PixelsInCentX*5.0*Sin(SubIndex*pi/180));
Y2 := CenterPageY-Trunc(PixelsInCentY*5.0*Cos(SubIndex*pi/180));
Moveto(X1,Y1);
Lineto(X2,Y2);
X2 := CenterPageX-Trunc(PixelsInCentX*5.0*Sin((SubIndex+2)*pi/180));
Y2 := CenterPageY-Trunc(PixelsInCentY*5.0*Cos((SubIndex+2)*pi/180));
Moveto(X1,Y1); Lineto(X2,Y2);
X2 := CenterPageX-Trunc(PixelsInCentX*5.0*Sin((SubIndex-2)*pi/180));
Y2 := CenterPageY-Trunc(PixelsInCentY*5.0*Cos((SubIndex-2)*pi/180));
Moveto(X1,Y1); Lineto(X2,Y2);
end;
for I:=1 to 71 do // Every 5 Degree
if I in [6,9,12,18,24,27,30,36,42,45,48,54,60,63,66] then else
begin
SubIndex := Index+(I*5); Normal360(SubIndex);
if (I mod 3)=0 then EE:=5.2 else EE:=5.5;
X1 := CenterPageX-Trunc(PixelsInCentX*6*Sin(SubIndex*pi/180));
Y1 := CenterPageY-Trunc(PixelsInCentY*6*Cos(SubIndex*pi/180));
X2 := CenterPageX-Trunc(PixelsInCentX*EE*Sin(SubIndex*pi/180));
Y2 := CenterPageY-Trunc(PixelsInCentY*EE*Cos(SubIndex*pi/180));
Moveto(X1,Y1);
Lineto(X2,Y2);
end;
for I := 1 to 359 do // Mini Lines Every Degree
if (I mod 5) = 0 then else
begin
SubIndex := Index+I; Normal360(SubIndex);
X1 := CenterPageX-Trunc(PixelsInCentX*6*Sin(SubIndex*pi/180));
Y1 := CenterPageY-Trunc(PixelsInCentY*6*Cos(SubIndex*pi/180));
X2 := CenterPageX-Trunc(PixelsInCentX*5.7*Sin(SubIndex*pi/180));
Y2 := CenterPageY-Trunc(PixelsInCentY*5.7*Cos(SubIndex*pi/180));
Moveto(X1,Y1);
Lineto(X2,Y2);
end;
end;
Printer.EndDoc;
except
on E: Exception do MessageDlg(E.Message, mtError, [mbok], 0);
end;
end;
end;
end.
สินค้าที่อาจเกี่ยวข้องจาก ร้านค้าออนไลน์