Drucken - Drucken mit der MFC (Doc-View)



  • Drucken und Druckvorschau in der MFC

    (wie man ein Projekt erstellt muss ich hoffentlich nicht mehr erklären 😉
    ihr müsst nur darauf achten die Druckerunterstützung zu aktvieren)

    Für unser Beispiel wollen wir einige Rechtecke auf dem Drucker ausgeben die über mehrere Seiten hinweg gezeichnet werden.

    Zuerst modifizieren wir die OnDraw() Funktion unseres Projekts so das sie ein Rechteck zeichnet.

    void CPrintView::OnDraw(CDC* pDC)
    {
       pDC->Rectangle(20,20,200,200);
    }
    

    Damit habt ihr schon eine funktionierende Druckerunterstützung - Gratuliere

    Aber wenn ihr das ausgedruckte mit dem auf dem Bildschirm vergleicht seht ihr das die Größenverhältnisse nicht stimmen. Das rechteck wird wesentlich kleiner ausgedruckt.

    Skalieren

    Der Grund warum das Rechteck kleiner ausgedruckt wird als es dargestellt wird ist der das die Punkte auf dem Drucker kleiner sind als auf dem Bildschirm. Hier sieht man auch die Auswirkungen des Standartmäßig vorgegebenen Abbildungsmodus "MM_TEXT".

    Dieses Problem lösen wir mit einem anderen Abbildungsmodus den wir folgendermaßen angeben:

    pDC->SetMapMode(MM_LOENGLISH);
    pDC->Rectangle(20,-20,220,-220);
    

    MM_LOENGLISH eignet sich besser zum arbeiten mit Grafiken da er als Maßeinheiten statt Punkt oder Pixel, ein hunderstel Inch verwendet.
    Bei pDC->Rectangle(20,-20,220,-220); fällt dem aufmerksamen Beobachter auf das wir plötzlich mit negativen werten arbeiten. Das liegt daran das MM_LOENGLISH die Koordinaten ander interpretiert.
    Normal: X-Koordinaten werden nach rechts größer, Y-Koordianten werden nach unten Größer
    MM_LOENGLISH: X-Koordinaten werden nach rechts Größer, Y-Koordinaten werden nach OBEN größer.
    Am Ende des Textes eine Tabelle mit den zur verfügung stehenden Modi

    ^
         +Y|           
           |           
     -X    |    +X     
    <-------------->
           |      
           |      
         -Y|
    

    Mehrere Seiten ausdrucken

    Zuerst brauchen wir eine Membervariable in unserem Document
    Dazu erstellen wir wie gewohnt die Membervariable m_numRects
    und initialisieren sie im Konstruktor des Documents:

    CPrint1Doc::CPrint1Doc():m_numRects(7)
    {
    	// ZU ERLEDIGEN: Hier Code für One-Time-Konstruktion einfügen
    
    }
    

    Nun modifizieren wir unser OnDraw() so das mehrere Rechtecke gezeichnet werden:

    void CPrint1View::OnDraw(CDC* pDC)
    {
    	CPrint1Doc* pDoc = GetDocument();
    	ASSERT_VALID(pDoc);
    	pDC->SetMapMode(MM_LOENGLISH);
    
    	CString s;
    	s.Format("%d", pDoc->m_numRects);
    	pDC->TextOut(300,-100,s);
    	for(int x=0; x<pDoc->m_numRects; x++)
    	{
    		pDC->Rectangle(20,-(20+x*200),220,-(220+x*200));
    	}
    }
    

    Schauen wir uns jetzt die Seitenansicht an sehen wir dass das 6. Rechteck ber die Seite hinaus ragt, auf der 2. Seite aber nichts angezeigt wird.
    Um das zu korrigieren müssen wir der MFC mitteilen wie viele Seiten ausgegeben werden sollen. Hierfür müssen wir die Funktion SetMaxPage() in der OnBeginPrinting() der Ansichtsklasse aufrufen.
    Als nächstes müssen wir die Seitenhöhe kennen. Dies lässt sich mit einem Aufruf der Funktion GetDeviceCaps() ermitteln. Um die vertikale Auflösung abzufragen, übergeben wir als Argument die Konstante VERTRES. Wenn wir HORZRES übergeben würden, erhalten wir die horizontale Auflösung.

    Es gibt 29 Konstanten die an GetDeviceCaps() übergeben werden können. U.a. NUMFONTS für die Anzahl der unterstützten Fonts und DRIVERVERSION für die Versionsnummer des Treibers. Eine vollständige Liste findet ihr in der MSDN

    // Vorher die Kommentarzeichen im Funktionskopf entfernen
    void CPrint1View::OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo)
    {
    	CPrint1Doc* pDoc = GetDocument();
    	ASSERT_VALID(pDoc);
    
    	int pageHeight	= pDC->GetDeviceCaps(VERTRES);
    	int logPixelsY	= pDC->GetDeviceCaps(LOGPIXELSY);
    	int rectHeight  = (int)(2.2 * logPixelsY);
    	int numPages	= 7 * rectHeight / pageHeight + 1;
    
    	pInfo->SetMaxPage(numPages);
    }
    

    Erstellen wir das Program jetzt noch einmal und schauen uns die Seitenansicht an so sehen wir das wir zwar inzwischen mehrere Seiten drucken könnten, der Seitenumbruch aber offensichtlich nicht funktioniert.

    Den Ursprung festlegen

    Damit die 2. und alle nachfolgenden Seiten korrekt ausgegeben werden müssen sie der MFC mitteilen wo die Seitenanfänge liegen. Zur Zeit zeichnet die MFC die Seiten genau so wie es ihr in OnDraw() vorgegeben wird, und zwar alle 7 Rechtecke vom begin der Seite bis zum Ende. Um der MFC mitzuteilen wo der neue Seitenanfang leigen soll, müssen wir zuerst die OnPrepareDC()-Funktion der Ansichtsklasse überschreiben.

    void CPrint1View::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo) 
    {
    	if(pDC->IsPrinting())
    	{
    		int pageHeight = pDC->GetDeviceCaps(VERTRES);
    		int originY = pageHeight * (pInfo->m_nCurPage - 1);
    		pDC->SetViewportOrg(0,-originY);
    	}
    	CView::OnPrepareDC(pDC, pInfo);
    }
    

    Das MFC Framework ruft OnPrepareDC() auf, kurz bevor es die Daten auf dem Bildschirm oder Drucker ausgiebt. Für den Fall das OnPrepareDC() vor der Ausgabe der Daten auf dem Bildschirm aufgerufen wird werden wir an der Standartverarbeitung von OnPrepareDC() nichts ändern. Aus diesem Grund prüfen wir mithilfe von IsPrinting() ob die Anwendung die Daten drucken will.
    Wenn ja müssen wir festlegen welche Daten auf die aktuelle seite gehören. Dazu benötigen wir die Höhe der Druckerseite in Punkten (GetDeviceCaps()).

    Als Nächstes müssen wir für die Anzeige einen neuen Viewport-Ursprung(die Position der Koordianten 0,0) festlegen.

    Wenn ihr das Programm nun ausführt seht ihr das die Seiten jetzt korrekt umgebrochen werden.

    Anhang

    Modus          |Einheit          |x                |y                |
    ---------------------------------------------------------------------|
    MM_HIENGLISH   |0,001 Inch       |Vergrößert rechts|Vergrößert oben  |
    MM_HIMETRIC    |0,01 Millimeter  |Vergrößert rechts|Vergrößert oben  |
    MM_ISOTROPIC   |Benutzerdefiniert|Benutzerdefiniert|Benutzerdefiniert|
    MM_ANISOTROPIC |Benutzerdefiniert|Benutzerdefiniert|Benutzerdefiniert|
    MM_LOENGLISH   |0,01 Inch        |Vergrößert rechts|Vergrößert oben  |
    MM_LOMETRIC    |0,1 Millimeter   |Vergrößert rechts|Vergrößert oben  |
    MM_TEXT        |Gerätepixel      |Vergrößert rechts|Vergrößert unten |
    MM_TWIPS       |1/1440 Inch      |Vergrößert rechts|Vergrößert oben  |
    

    Memberfunktionen und -variablen der Klasse CPrintInfo

    Klassenelement     | Beschreibung
    -----------------------------------------------------------------------------
    SetMaxPage()       |Setzt die maximale Seitenzahl des Dokuments
    -----------------------------------------------------------------------------
    SetMinPage()       |Setzt die minimale Seitenzahl des Dokuments
    -----------------------------------------------------------------------------
    GetFromPage()      |Ermittelt die Nummer der ersten Seite, die der Anwender
                       |ausdrucken möchte.
    -----------------------------------------------------------------------------
    GetMaxPage()       |Ermittelt die maximale Seitenzahl des Dokuments, die in
                       |[i]OnPreparePrinting()[/i] geändert worden sein kann.
    -----------------------------------------------------------------------------
    GetMinPage()       |Ermittelt die minimale Seitenzahl des Dokuments, die in
                       |[i]OnPreparePrinting()[/i] geändert worden sein kann.
    -----------------------------------------------------------------------------
    GetToPage()        |Ermittelt die Nummer der letzten Seite, die der Anwender
                       |ausdrucken möchte.
    -----------------------------------------------------------------------------
    m_bContinuePrinting|Steuert den Druckprozess. Wird das Flag FALSE gesetzt
                       |endet der Druckjob
    -----------------------------------------------------------------------------
    m_bDirect          |Zeigt an, ob das Dokument zurzeit gedruckt wird
    -----------------------------------------------------------------------------
    m_bPreview         |Zeigt an, ob das Dokument zurzeit in der Druckvorschau
                       |steht
    -----------------------------------------------------------------------------
    m_nCurPage         |enthält die aktuelle Nummer der Seite die gerade gedruckt
                       |wird
    -----------------------------------------------------------------------------
    m_nNumPreviewPages |Enthällt die Anzahl der Seiten(eine oder zwei) die in der
                       |Druckvorschau angezeigt werden.
    -----------------------------------------------------------------------------
    m_pPD              |Enthällt einen Zeiger auf das PrintDialog-Objekt des
                       |Druckjobs
    -----------------------------------------------------------------------------
    m_rectDraw         |Enthällt ein Rechteck, das den nutzbaren Bereich für die 
                       |aktuelle Seite definiert
    -----------------------------------------------------------------------------
    m_strPageDesc      |Enthällt einen Formatstring für die Seitennummer.
    -----------------------------------------------------------------------------
    

Anmelden zum Antworten