Um den maximalen Druckbereich zu bestimmen, kann man folgende Werte aus GetDeviceCaps() nutzen:
bereits gesagt hat, werden die 'device units' ebenfalls als Pixel geliefert.
Wie Lexikos ebenfalls gesagt hat, kann die Function TextOut() keine Zeilen umbrechen. Er hat empfohlen, stattdessen eine 'leistungsfähigere' Funktion wie DrawText() zu verwenden. Das ist schon mal ganz gut, wenn der Text auf eine Seite passt. Passt er nicht, muss man allerdings die 'noch leistungsfähigere' Funktion DrawTextEx() verwenden. Die hat den Vorteil, dass sie im zusätzlichen Parameter DRAWTEXTPARAMS zurückgibt, bis zu welchem Zeichen sie gekommen ist, bevor Text abgeschnitten wurde. Wenn dieser Wert nicht der Länge der übergebenen Zeichenfolge entspricht, konnte ein Teil des Textes nicht gedruckt werden. Er muss auf einer weiteren Seite ausgegeben werden.
Der Funktion DrawTextEx() muss man ein Rechteck übergeben, in das der Text ausgegeben werden soll. Die Koordinaten dieses Rechtecks beziehen sich anscheinend auf den bedruckbaren Bereich der Seite, d.h.
füllt jedenfalls den gesamten verfügbaren Druckbereich.
Ränder werden bis auf den von England beeinflussten Bereich der Welt üblicherweise in mm/cm gesetzt. Die Angaben für das Rechteck benötigen aber Pixel. Wieviele Pixel ergeben aber 1 cm? Hier helfen die Werte LOGPIXELSX/LOGPIXELSY weiter, die die Auflösung in "Pixel per Inch" liefern. Ein Inch/Zoll entspricht etwa 2,54 cm. Teilt man den Wert aus LOGPIXELSX durch 2,54, erhält man die Anzahl der Pixel für einen nahezu 1 cm breiten horizontalen Rand. Wenn man Seitenränder setzen will, beziehen die sich aber üblicherweise auf den physischen Seitenrand. Will man das Rechteck entsprechend anpassen, muss man deshalb die Distanzen zwischen physischem Rand und Druckbereich abziehen.
Das hier habe ich inzwischen für die Druckausgabe auf den Standarddrucker entwickelt. Der Funktion PrintStr() werden ein String und optional ein Font übergeben. Die Funktion versucht, den übergebenen Font möglichst genau an die Druckerauflösung angepasst für den Ausdruck zu nutzen; Standard ist Arial 10 Punkt. Außerdem setzt die Funktion hartcodierte Seitenränder von etwa 20 mm. Zeilen und Seitenumbrüche scheinen recht zuverlässig zu funktionieren. Ich musste dafür aber das Flag DT_EDITCONTROL setzen. Ansonsten können am Ende der Seite Teile von Zeilen gedruckt werden, wenn das Rechteck nicht genau passt.
Code: Select all
#NoEnv
SetBatchLines -1
Lorem =
(Join
Lorem ipsum dolor sit amet consectetuer nulla vitae et felis nonummy. Tempor quis volutpat risus consectetuer Phasellus et quam
congue nec est. Volutpat Sed Vestibulum ridiculus montes tincidunt ac Pellentesque tempor leo Duis. Amet wisi at pretium et
faucibus semper at Curabitur pretium at. Et Morbi Nullam tincidunt condimentum at nunc egestas Maecenas leo et. Dolor eros montes
In Morbi dignissim consequat lacinia amet ut Duis. Et leo eros.
`r`n`r`n
Turpis volutpat sodales feugiat odio quis id netus facilisis ac a. Cursus congue dolor urna urna pellentesque tellus nascetur
facilisis Sed laoreet. Sem lacus porta id wisi consectetuer id Donec elit at.
`r`n`r`n
Cursus vel non feugiat at Aenean interdum nec tellus Ut Donec. Tortor Aliquam sit dui Vivamus nec dui dapibus metus amet feugiat.
Ac ridiculus Donec ipsum et et Curabitur leo mollis sagittis vitae. Facilisis Nam nec tellus velit tincidunt dapibus ac adipiscing.
`r`n`r`n
Penatibus In netus tristique egestas tincidunt risus risus malesuada convallis tellus. Facilisi Sed Maecenas ultrices sem auctor
netus scelerisque accumsan ac egestas. Neque vel elit a enim euismod ac vitae tincidunt porttitor laoreet. Interdum urna nibh at
nunc aliquet Fusce hac semper lacinia elit. Tellus tortor Ut sapien interdum orci vel enim sed Nam arcu. Nam id justo mauris nunc
Donec justo id pede Lorem lacinia. Eget parturient turpis Donec consequat tempus lobortis tortor id Suspendisse Nam. Justo amet.
)
EditText := Lorem
Loop, 3
EditText .= "`r`n`r`n" . Lorem
; ----------------------------------------------------------------------------------------------------------------------------------
Gui, Margin, 10, 10
Gui, Font, s10, Arial
Gui, Add, Edit, xm ym w600 r20 hwndHED, %EditText%
Gui, Add, Button, gPrint vBtnPrint Default, Print
GuiControl, Focus, BtnPrint
Gui, Show, , Print Edit
Return
; ----------------------------------------------------------------------------------------------------------------------------------
GuiClose:
GuiEscape:
ExitApp
; ----------------------------------------------------------------------------------------------------------------------------------
Print:
ControlGetText, Str, , ahk_id %HED% ; it's important to use ControlGetText if you read the text from an Edit control
If (Str) {
If !PrintStr(Str)
MsgBox, 0, PrintStr, An error occurred!`nErrorLevel = %ErrorLevel%
}
Return
; ==================================================================================================================================
; Prints the passed string on the default printer
; Parameters:
; Str - string to print
; FontName - name of the font to be used for printing like the FontName parameter of the 'Gui, Font' command
; Default: Arial
; FontSize - size of the font in points
; Default: 10
; FontOpts - other font options like the Options parameter of the 'Gui, Font' command
; Default: s10
; Return values:
; On success: True
; On failure: False
; Errorlevel contains one of the following values:
; 1 - the specified font is not available
; 2 - error when calling the PrintDlg API function
; 3 - couldn't retrieve a valid DC for the printer
; 4 - an error occured while trying to print
; Remarks:
; Based on the code published by Lexikos at autohotkey.com/board/topic/20468-detecting-printer-printing-text/page-2#entry146062
; ==================================================================================================================================
PrintStr(Str, FontName := "Arial", FontSize := 10, FontOpts := "") {
Static DISize := A_PtrSize * 5 ; size of DOCINFO structure
Static DPSize := 20 ; size of DRAWTEXTPARAMS structure
Static LFSize := A_IsUnicode ? 60 : 92 ; size of LOGFONT structure
Static PDSize := A_PtrSize = 8 ? (A_PtrSize * 13) + 16 : 66 ; size of PRINTDLG structure
Static Margins := 20 ; left, top, right, and bottom margins in millimeters
Static DocName := "PrintStr" ; document name
; Get a HFONT handle and the LOGFONT structure for the passed font (lazy method)
Gui, PrintStrGUI: Font, %FontOpts% q2 s%FontSize%, %FontName%
Gui, PrintStrGUI: Add, Text, hwndHTX, Dummy!
HFONT := DllCall("SendMessage", "Ptr", HTX, "UInt", 0x0031, "Ptr", 0, "ptr", 0, "UPtr") ; WM_GETFONT
Gui, PrintStrGUI: Destroy
VarSetCapacity(LOGFONT, LFSize, 0) ; LOGFONT
DllCall("GetObject", "Ptr", HFONT, "Int", LFSize, "Ptr", &LOGFONT)
If (FontName <> StrGet(&LOGFONT + 28))
Return (ErrorLevel := 1) & 0
; Get a device context of the default printer
VarSetCapacity(PRINTDLG, PDSize, 0) ; PRINTDLG
NumPut(PDSize, PRINTDLG, 0, "UInt")
NumPut(0x0100 | 0x0400, PRINTDLG, A_PtrSize * 5, "UInt")
If !(DllCall("Comdlg32.dll\PrintDlg", "Ptr", &PRINTDLG, "Int"))
Return (ErrorLevel := 2) & 0
DllCall("GlobalFree", "Ptr", NumGet(PRINTDLG, A_PtrSize * 2, "UPtr"))
DllCall("GlobalFree", "Ptr", NumGet(PRINTDLG, A_PtrSize * 3, "UPtr"))
If !(HDC := NumGet(PRINTDLG, A_PtrSize * 4, "UPtr"))
Return (ErrorLevel := 3) & 0
; Get the device specific values
DPIX := DllCall("GetDeviceCaps", "Ptr", HDC, "Int", 0x58) ; LOGPIXELSX (horizontal resolution)
, DPIY := DllCall("GetDeviceCaps", "Ptr", HDC, "Int", 0x5A) ; LOGPIXELSY (vertical resolution)
, PageW := DllCall("GetDeviceCaps", "Ptr", HDC, "Int", 0x08) ; HORZRES (width of the printable area)
, PageH := DllCall("GetDeviceCaps", "Ptr", HDC, "Int", 0x0A) ; VERTRES (height of the printable area)
, PhysW := DllCall("GetDeviceCaps", "Ptr", HDC, "Int", 0x6E) ; PHYSICALWIDTH (physical width in device units)
, PhysH := DllCall("GetDeviceCaps", "Ptr", HDC, "Int", 0x6F) ; PHYSICALHEIGHT (physical height in device units)
, OffsL := DllCall("GetDeviceCaps", "Ptr", HDC, "Int", 0x70) ; PHYSICALOFFSETX (physical printable area x margin)
, OffsT := DllCall("GetDeviceCaps", "Ptr", HDC, "Int", 0x71) ; PHYSICALOFFSETY (physical printable area y margin)
, OffsR := PhysW - PageW - OffsL ; physical printable area right offset
, OffsB := PhysH - PageH - OffsT ; physical printable area bottom offset
, HorzM := Round((DPIX / 25.4) * Margins) ; horizontal margins (~ 20 mm)
, VertM := Round((DPIY / 25.4) * Margins) ; vertical margins (~ 20 mm)
; Set the printing rectangle
RectL := HorzM - OffsL ; left
, RectT := VertM - OffsT ; top
, RectR := PageW - HorzM + OffsR ; right
, RectB := PageH - VertM + OffsB ; bottom
; Scale the font height according to the vertical resolution of the printer
FontH := NumGet(LOGFONT, 0, "Int") ; lfHeight
, NumPut(Round(-FontSize * DPIY / 72), LOGFONT, 0, "Int")
, NumPut(0, LOGFONT, 4, "Int") ; lfWidth
, HFONT := DllCall("CreateFontIndirect", "Ptr", &LOGFONT, "UPtr")
; Select the scaled font
DllCall("SelectObject", "Ptr", HDC, "Ptr", HFONT)
; Prepare for printing
VarSetCapacity(DOCINFO, DISize, 0) ; DOCINFO
, NumPut(DISize, DOCINFO, "UInt")
, NumPut(&DocName, DOCINFO, A_PtrSize, "UPtr")
VarSetCapacity(DTPARAMS, DPSize, 0) ; DRAWTEXTPARAMS
, NumPut(DPSize, DTPARAMS, "UInt")
VarSetCapacity(RECT, 16, 0)
, NumPut(RectL, RECT, 0, "Int")
, NumPut(RectT, RECT, 4, "Int")
, NumPut(RectR, RECT, 8, "Int")
, NumPut(RectB, RECT, 12, "Int")
RC := 0
; Print
If DllCall("StartDoc", "Ptr", HDC, "Ptr", &DOCINFO, "UInt") {
Loop {
Len := StrLen(Str)
If DllCall("StartPage", "Ptr", HDC, "Int") {
RC := DllCall("DrawTextEx", "Ptr", HDC, "Ptr", &Str, "Int", Len, "Ptr", &RECT, "UInt", 0x2250, "Ptr", &DTPARAMS, "Int")
DllCall("EndPage", "Ptr", HDC, "Int")
}
If (RC) {
LD := NumGet(DTPARAMS, 16, "UInt") ; uiLengthDrawn
Str := LD < Len ? SubStr(Str, LD + 1) : ""
}
} Until (RC = 0) || (Str = "")
DllCall("EndDoc", "Ptr", HDC)
}
DllCall("DeleteDC", "Ptr", HDC)
If (HFONT)
DllCall("DeleteObject", "Ptr", HFONT)
Return (RC ? 1 : (ErrorLevel := 4) & 0)
}