Printrequester via Windows-Api selbst gestrickt

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
hjbremer
Beiträge: 822
Registriert: 27.02.2006 22:30
Computerausstattung: von gestern
Wohnort: Neumünster

Printrequester via Windows-Api selbst gestrickt

Beitrag von hjbremer »

Da Drucken anscheinend nur eine Minderheit tut, hat sich seit Jahren bei PB nix getan.
Besonders die Einstellungen im PrintRequester sind nicht verfügbar. Dabei würde es doch schon reichen die RadioButtons für "alles Drucken" oder "Markiert" abzufragen.

Die im Forum etc verfügbaren Codes sind alle recht aufwändig, da diese oft die Voreinstellungen ändern wollen. Sie funktionieren nicht immer und verstehen tut Sie der normale HobbyUser wie ich es bin auch nicht so recht.

Hier mal der Versuch einen simplen eigenen Printrequester für Windows zu schreiben.
Voreinstellungen + Abfragen gibt es nur für die RadioButtons im Seitenbereich und für Ausgabe in Datei.
Und man kann keine Drawing-PB Befehle benutzen. Nur Windows-Api. Dies gilt ab PB 4.4

Ersatz für PrintRequester

Code: Alles auswählen

Procedure.i Prn_PrintRequester(*pd.PRINTDLG) 
Protected ok = 0

*pd\lStructSize = SizeOf(PRINTDLG) 
*pd\hwndOwner   = WindowID(GetActiveWindow())  ;oder null 
*pd\hDevMode    = 0
*pd\hDevNames   = 0

*pd\nMinPage = 1    ;wenn definiert = Startseite, 
                    ;kann auch Vorgabe sein
                    ;wenn aber nMaxPage fehlt, kein PrintDlg 

*pd\nMaxPage = -1   ;nicht definiert = keine Seitenangabe

;*pd\nFromPage = 3  ;wenn definiert, erscheinen diese 
;*pd\nToPage   = 5  ;Werte in der Editbox
                    ;kann auch Vorgabe sein

*pd\Flags | #PD_RETURNDC        ;muß sein !!!!!
;*pd\Flags | #PD_PRINTSETUP

;folgendes kann auch Vorgaben sein
;*pd\Flags | #PD_HIDEPRINTTOFILE ;Checkbox in Datei drucken ist weg
;*pd\flags | #PD_NOPAGENUMS      ;RadioButton Seiten ist weg
;*pd\flags | #PD_NOSELECTION     ;RadioButton Markierung ist weg 

;den RadioButton Aktuelle Seite gibt es nur mit PrinDlgEx
;PrinDlgEx macht allerdings viel mehr Arbeit

ok = PrintDlg_(*pd)
If ok: ok = *pd\hDC: EndIf

ProcedureReturn ok   
EndProcedure 

Procedure.i Prn_StartPrinting(*pd.PRINTDLG, jobname$)
Protected ok = 0
Protected szOutput = 0

  ;in eine Datei drucken ist praktisch, wenn man
  ;den Windows Standard Generic / Text only Treiber
  ;installiert hat. Dann kann man sich das Ergebnis 
  ;sehr schön mit Wordpad ansehen.
  If *pd\flags & #PD_PRINTTOFILE  ;kann auch weggelassen werden
     szOutput = @"Test.txt"       ;dann kommt ein Fenster
  EndIf                           ;um den Dateinamen einzugeben
  
  DocInfo.DOCINFO 
  DocInfo\cbSize = SizeOf(DOCINFO) 
  DocInfo\lpszDocName = @jobname$ 
  DocInfo\lpszOutput = szOutput
  
  ok = StartDoc_(*pd\hDC, @DocInfo)
  If ok < 1: ok = 0: EndIf  
  
ProcedureReturn ok
EndProcedure

Procedure.i Prn_StopPrinting(dc)
  
  EndDoc_(dc)
  DeleteObject_(dc)
  DeleteDC_(dc)   
   
EndProcedure
Und nun eine Demo dafür, erhebt keinen Anspruch auf genaues Drucken

Code: Alles auswählen

; Demo Prozeduren---------------------------------------------

Structure GetDeviceCaps
 prnhorzres.i
 prnhorzsize.i
 prnhorzdotmm.f
 prnhorzoffmm.f
 prnvertres.i
 prnvertsize.i
 prnvertdotmm.f
 prnvertoffmm.f
 wndhorzres.i
 wndhorzsize.i
 wndhorzdotmm.f
 wndvertres.i
 wndvertsize.i
 wndvertdotmm.f
 faktorH.f
 faktorV.f
EndStructure

Procedure.i Prn_GetDeviceCaps(dc, *gdc.GetDeviceCaps)

;Bereich in mm
*gdc\prnhorzsize = GetDeviceCaps_(dc, #HORZSIZE) 
*gdc\prnvertsize = GetDeviceCaps_(dc, #VERTSIZE) 

;Anzahl Dots, #PHYSICALWIDTH wäre genauer, aber vergrößert alles
*gdc\prnhorzres  = GetDeviceCaps_(dc, #HORZRES)  ;#PHYSICALWIDTH 
*gdc\prnvertres  = GetDeviceCaps_(dc, #VERTRES)  ;#PHYSICALHEIGHT

;dot pro mm 
*gdc\prnhorzdotmm = *gdc\prnhorzres / *gdc\prnhorzsize   
*gdc\prnvertdotmm = *gdc\prnvertres / *gdc\prnvertsize     

;nicht druckbarer Rand in mm, etwas zu klein wegen #HORZRES #VERTRES 
*gdc\prnhorzoffmm = GetDeviceCaps_(dc, #PHYSICALOFFSETX) / *gdc\prnhorzdotmm
*gdc\prnvertoffmm = GetDeviceCaps_(dc, #PHYSICALOFFSETY) / *gdc\prnvertdotmm

dc = GetWindowDC_(0)
 
;Bereich in mm
*gdc\wndhorzsize = GetDeviceCaps_(dc, #HORZSIZE) 
*gdc\wndvertsize = GetDeviceCaps_(dc, #VERTSIZE) 

;Anzahl Dots
*gdc\wndhorzres  = GetDeviceCaps_(dc, #HORZRES)
*gdc\wndvertres  = GetDeviceCaps_(dc, #VERTRES)

;dot pro mm 
*gdc\wndhorzdotmm = *gdc\wndhorzres / *gdc\wndhorzsize   
*gdc\wndvertdotmm = *gdc\wndvertres / *gdc\wndvertsize   

;dies ist der Umrechnungswert Window to Printer Auflösung
*gdc\faktorH = *gdc\prnhorzdotmm / *gdc\wndhorzdotmm   
*gdc\faktorV = *gdc\prnvertdotmm / *gdc\wndvertdotmm   

ReleaseDC_(0, dc)

EndProcedure

Procedure.i Prn_GetFontHoehe(fontid)
Protected lg.LOGFONT
Protected pixely = GetDeviceCaps_(GetDC_(0), #LOGPIXELSY)
Protected retvalue = GetObject_(fontid, SizeOf(LOGFONT), lg) 
Protected fonthoehe = -MulDiv_(lg\lfHeight, 72, pixely)   
ProcedureReturn fonthoehe
EndProcedure                  

Procedure.s Prn_GetFontName(fontid)
Protected lg.LOGFONT
GetObject_(fontid, SizeOf(LOGFONT), lg) 
ProcedureReturn PeekS(@lg\lfFaceName)
EndProcedure

; Demo---------------------------------------------------

Procedure Drucken(pbnr)

;falls Fontname + Höhe unbekannt
fontid = GetGadgetFont(pbnr)        
prnfont$ = Prn_GetFontName(fontid)
prnfonthh = Prn_GetFontHoehe(fontid) 

printdlg.printdlg

dc = Prn_PrintRequester(printdlg)  
     If Not dc: ProcedureReturn: EndIf  

     ;Druckername holen, wozu auch immer
      *dn.DEVNAMES = GlobalLock_(printdlg\hDevNames) 
      prnname$ = PeekS(*dn + *dn\wDeviceOffset)
      GlobalUnlock_(printdlg\hDevNames)

Prn_StartPrinting(printdlg, "Druckjobname")  

   Prn_GetDeviceCaps(dc, caps.GetDeviceCaps)

   prnfontnr = LoadFont(#PB_Any, prnfont$, prnfonthh * caps\faktorV)

   randoben = 20 - caps\prnvertoffmm   ;in mm 20 - nichtdruckbarer Bereich
   randlinks = 10 - caps\prnhorzoffmm  ;in mm
   zeilenabstand = 2                   ;in mm
   
   zeilenabstand = zeilenabstand * caps\prnvertdotmm
   zeilenhoehe = prnfonthh * caps\faktorV 
     
   x = (caps\prnvertsize - randoben - randoben) * caps\prnvertdotmm
   zeilenproseite = x / (zeilenabstand + zeilenhoehe)
      
   zeilengesamt = CountGadgetItems(pbnr)  
   
   ;RadioButton Markierung gedrückt ?
   selflag = printdlg\flags & #PD_SELECTION
   If selflag
      zeilengesamt = SendMessage_(GadgetID(pbnr), #LVM_GETSELECTEDCOUNT, 0, 0)
      istart = -1    ;Startwert für #LVM_GETNEXTITEM
   EndIf 

   If Not zeilengesamt: ProcedureReturn: EndIf
   
   ;Anzahl Seiten für Message und Ausdruck 
   seitenanzahl = zeilengesamt / zeilenproseite
   If zeilengesamt % zeilenproseite: seitenanzahl + 1: EndIf 

   seitevon = 1: seitebis = seitenanzahl   
   
   ;RadioButton Seiten gedrückt ?
   If printdlg\flags & #PD_PAGENUMS
      seitevon = printdlg\nFromPage
      seitebis = printdlg\nToPage
   EndIf
   
   lfdnr = (seitevon - 1) * zeilenproseite  

   ;es geht los
   SetBkMode_(dc, #TRANSPARENT)
   SetTextAlign_(dc, #TA_TOP)  
   SelectObject_(dc, FontID(prnfontnr))   
   
   startspalte = randlinks * caps\prnhorzdotmm
   startzeile  = randoben  * caps\prnvertdotmm
      
   StartPage_(dc) 
      
      For seite = seitevon To seitebis  
      
         x = startspalte
         y = startzeile
   
         For j = 1 To zeilenproseite 
            
            If lfdnr < zeilengesamt 
               If selflag
                  nextitem = SendMessage_(GadgetID(pbnr), #LVM_GETNEXTITEM, istart, #LVNI_SELECTED) 
                  istart = nextitem    ;für nächstes Item
                  text$ = GetGadgetItemText(pbnr, nextitem)        
               Else
                  text$ = GetGadgetItemText(pbnr, lfdnr)
               EndIf
               
               lfdnr + 1
                        
               TextOut_(dc, x, y, @text$, Len(text$)) 
               y + zeilenabstand + zeilenhoehe ;oder zeilenhoehe mit GetTextMetrics() ermitteln

            EndIf

         Next      
         EndPage_(dc)
      
      Next
      
Prn_StopPrinting(dc) 

If IsFont(prnfontnr): FreeFont(prnfontnr): EndIf

EndProcedure
   
; -------------------------------------------------------

Enumeration
 #but0
 #lvg1
EndEnumeration

font1 = LoadFont(#PB_Any, "Arial", 9)

OpenWindow(#PB_Any, 100, 100, 600, 500, "DruckTest") 

flags = #PB_ListIcon_MultiSelect
flags | #PB_ListIcon_FullRowSelect
flags | #PB_ListIcon_AlwaysShowSelection
ListIconGadget(#lvg1, 10, 10, 500, 400, "0", 400, flags)
SetGadgetFont(#lvg1, FontID(font1))

AddGadgetItem(#lvg1, 0, "1 qqggmarkieren Sie ein paar Zeilen")
AddGadgetItem(#lvg1, 1, "2 ÖÜÖÜdrücken Sie den Button drucken")
AddGadgetItem(#lvg1, 2, "3 und im Printrequester unten links")
AddGadgetItem(#lvg1, 3, "4 den RadioButton Markierung")
AddGadgetItem(#lvg1, 4, "5 dann werden nur die markierten Zeilen gedruckt")
For j = 5 To 90
 AddGadgetItem(#lvg1, j, Str(j+1))
Next

ButtonGadget(#but0, 10, 450, 99, 25, "Drucken")

Repeat: event = WaitWindowEvent(1) 
    
  If Event = #PB_Event_Gadget Or Event = #PB_Event_Menu 
          
     welcherButton = EventGadget()   
     Select welcherButton
      
         Case #but0: Drucken(#lvg1)
           
     EndSelect
  
  EndIf

Until event = #PB_Event_CloseWindow 

End 

;allgemeiner Hinweis
; wer auf 1/10 mm genau drucken will/muß
; der muß alle Variablen die mit vertikalen 
; und horizontalen Maßen zu tun haben, auf Float setzen
; z.B. zeilenabstand, zeilenhoehe, sp, ze, x, y etc
; außerdem die korrekten Werte für Zeilenhöhe etc herausfinden

;falls Fontname + Höhe unbekannt; nur für Editorgadget drucken
; If GadgetType(pbnr) = #PB_GadgetType_Editor ; !!!
;    cf.CHARFORMAT
;    cf\cbSize = SizeOf(CHARFORMAT)
;    cf\dwMask = #CFM_SIZE |#CFM_FACE
;    SendMessage_(GadgetID(pbnr), #EM_GETCHARFORMAT, 0, cf)
;    prnfont$ = PeekS(@cf\szFaceName)
;    prnfonthh = cf\yHeight / 20
; Else
;    fontid = GetGadgetFont(pbnr)        
;    prnfont$ = Prn_GetFontName(fontid)
;    prnfonthh = Prn_GetFontHoehe(fontid) 
; EndIf
Purebasic 5.70 x86 5.72 X 64 - Windows 10

Der Computer hat dem menschlichen Gehirn gegenüber nur einen Vorteil: Er wird benutzt
grüße hjbremer