CListCtrl mit Imag´s drucken
-
Hallo,
ich habe eine MFC Anwendung. In meinem Programm habe ich ein dialogbasierte Fenster mit CListCtrl, wie man auf dem Bild zu sehen ist.
http://www.fh-augsburg.de/~nenov/drucken.jpg
Ich möchte dasganze ausdrucken. Problematisch für mich sind die Imag´s.Weißt jemand wie man Image´s in CListCtrl ausdruckt ???
Meine bisherige CODE:
for(int i=0; i < nAnzahl; i++){ nLaufendeNr++; // Ausruckbare Artikel auf 20 begrenzen if(i >= 20) { MessageBox("Es werden nur die ersten 20 Artikel ausgedruckt!", "Info!", MB_ICONEXCLAMATION); break; } // Einträge aus Listenelement lesen m_strProdukt = m_cList.GetItemText(i, 0); m_strHersteller = m_cList.GetItemText(i, 1); m_strPreis = m_cList.GetItemText(i, 2); m_strVerfuegbar = m_cList.GetItemText(i, 3); // und ausgeben dcPrint.TextOut(80, -550-nLaufendeNr*80, m_strProdukt); /* HIER SOLLEN DIE ICON´S EINGEFÜHGT WERDEN*/ } // Seite auswerfen dcPrint.EndPage(); // Dokument schließen dcPrint.EndDoc(); // Druckergerätekontext löschen dcPrint.DeleteDC(); MessageBox("Daten wurden erfolgreich gedruckt", "Info", MB_ICONEXCLAMATION); }
MSDN Library , http://www.codeproject.com/ und soweiter habe ich mir schon angeschaut.
-
Du musst dir die Images aus der CImageList holen und selbst beim ausdrucken zeichnen
-
Könntest du bitte etwas genauer sein.
-
Du hast vermutlichweise ja die Bilder einer CImageList hinzugefügt, die du bei dem hinzufügen der einzelnen Items verwendest.
Nun musst du beim drucken überprüfen welches Bild der Eintrag hat und dies wie dein Text selbst in der Ausgabe zeichnen.
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/vclrfcimagelistdrawex.asp
-
Könntest du mir bitte kleines Beispiel zeigen, wie ich DrawEx(...) beim drucken benutzen kann. Es ist mir schwierig zu verstehen
-
Don_Pazo schrieb:
Könntest du mir bitte kleines Beispiel zeigen, wie ich DrawEx(...) beim drucken benutzen kann. Es ist mir schwierig zu verstehen
Die Draw Funktion von CImageList tut es übrigens auch. Hab ich zumindest so eben festgestellt.
http://msdn.microsoft.com/library/en-us/vclib/html/_mfc_cimagelist.3a3a.draw.aspvoid CPrintImageListView::OnDraw(CDC* pDC) { CPrintImageListDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // ZU ERLEDIGEN: Hier Code zum Zeichnen der ursprünglichen Daten hinzufügen m_ImageList.Draw(pDC,1,CPoint(50,50),ILD_NORMAL); }
-
Ich kann einfach die schei..... Farben nicht drucken.
Das ist meine Funktion, bitte nicht erschrecken:
void CAnalyseNr4::OnDrucken() { CPrintDialog dlgPrint(FALSE, PD_ALLPAGES, this); CString m_strProdukt = ""; CString m_strHersteller = ""; CString m_strPreis = ""; CString m_strVerfuegbar =""; // GetDefaults liefert den Standarddrucker dlgPrint.GetDefaults(); // Verbinden des Drucker-DC mit einem CDC-Objekt CDC dcPrint; dcPrint.Attach(dlgPrint.GetPrinterDC()); // DOCINFO-Struktur erzeugen (wird für Druck benötigt) DOCINFO ListControlPrint; ListControlPrint.cbSize = sizeof(ListControlPrint); ListControlPrint.lpszDocName = "Listenelement Druck"; ListControlPrint.lpszOutput = NULL; ListControlPrint.lpszDatatype = NULL; ListControlPrint.fwType = NULL; //Maße des druckbaren Bereiches des Papiers ermitteln (in 0,1mm) dcPrint.SetMapMode(MM_LOMETRIC); int nLaenge = dcPrint.GetDeviceCaps(VERTSIZE); int nBreite = dcPrint.GetDeviceCaps(HORZSIZE); int nRechts = nBreite * 10 - 40; int nUnten = -nLaenge * 10 + 40; // Rahmen für Druck festlegen dcPrint.Rectangle(50, 0, nRechts, nUnten); // Schriftart und Grösse für die Überschrift festlegen CFont font, *p_OldFont; font.CreateFont(-100, 0, 0, 0, 600, 0, 0, 0, ANSI_CHARSET, OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, "Verdana"); p_OldFont= dcPrint.SelectObject(&font); // Ausdruck des Dokuments starten if (dcPrint.StartDoc(&ListControlPrint)>=0) { // Eine Seite beginnen dcPrint.StartPage(); // Mit grosser Schrift Überschrift ausgeben dcPrint.TextOut(450, -100, " Listenelement Druck"); // Standard Font für den Rest benutzen dcPrint.SelectObject(p_OldFont); // Obere Linie zeichnen (von links nach rechts) dcPrint.MoveTo(50, -500); dcPrint.LineTo(nRechts, -500); // Header ausgeben +++++++++++++++++++++++ dcPrint.TextOut(200,-530, "Produkt"); dcPrint.TextOut(800,-530, "Hersteller"); dcPrint.TextOut(1350,-530, "Preis"); dcPrint.TextOut(1680,-530, "Verfügbar?"); // Linie unter dem Header zeichnen (von links nach rechts) dcPrint.MoveTo(50, -600); dcPrint.LineTo(nRechts, -600); // Zweite Linie unter dem Header zeichnen (von links nach rechts) dcPrint.MoveTo(50, -605); dcPrint.LineTo(nRechts, -605); // Linie ganz unten zeichnen (von links nach rechts) dcPrint.MoveTo(50, nUnten+450); dcPrint.LineTo(nRechts, nUnten+450); // Ab hier kommen die vertikalen Linien (von oben nach unten) // Line ganz nRechts zeichnen (von oben nach unten) dcPrint.MoveTo(nRechts, -500); dcPrint.LineTo(nRechts, nUnten+450); // Zweite Linie von rechts zeichnen, also zwischen Preis und Verfügbar dcPrint.MoveTo(1600, -500); dcPrint.LineTo(1600, nUnten+450); // nächste Linie zeichnen, also Linie zwischen Hersteller und Preis dcPrint.MoveTo(1180, -500); dcPrint.LineTo(1180, nUnten+450); // nächste Linie, also zwischen Produkt und Hersteller dcPrint.MoveTo(630, -500); dcPrint.LineTo(630, nUnten+450); // Ganz linke Linie zeichnen dcPrint.MoveTo(50, -500); dcPrint.LineTo(50, nUnten+450); //Zeit und Datum ausgeben CTime time = CTime::GetCurrentTime(); CString date = time.Format("Datum: %d.%m.%Y "); CString str_Time = time.Format("Uhrzeit: %H:%M"); dcPrint.TextOut(50, -350, date); dcPrint.TextOut(50, -400, str_Time); // Ausgabe der Elemente des Listenelements CString str, m_strPreis, m_strVerfuegbar; // Seitenzahl ausgeben int nSeite= 1; str.Format("Seite %d ",nSeite); dcPrint.TextOut(1000, nUnten+250, str); // Ab hier wird der Ausdruck der Artikel vorbereitet // Ermitteln der Zeilen des Listenelement int nAnzahl = m_cList.GetItemCount(); int nLaufendeNr = 0; // !!!!!!!!!!!!!!!!!!!! HICON hIcon = NULL; for(int i=0; i < nAnzahl; i++) { nLaufendeNr++; // Ausruckbare Artikel auf 20 begrenzen if(i >= 20) { MessageBox("Es werden nur die ersten 20 Artikel ausgedruckt!", "Info!", MB_ICONEXCLAMATION); break; } // Einträge aus Listenelement lesen m_strProdukt = m_cList.GetItemText(i, 0); m_strHersteller = m_cList.GetItemText(i, 1); m_strPreis = m_cList.GetItemText(i, 2); m_strVerfuegbar = m_cList.GetItemText(i, 3); // und ausgeben dcPrint.TextOut(80, -550-nLaufendeNr*80, m_strProdukt); // !!! WAS SOLL BITTE SCHÖN HIER SEIN, DAMIT ICH DIE FARBEN DRUCKEN KANN !!! hIcon = AfxGetApp()->LoadIcon(IDR_GRUEN); dcPrint.DrawIcon(CPoint(50,50), hIcon); //dcPrint.TextOut(650, -550-nLaufendeNr*80, m_strHersteller); //dcPrint.TextOut(1200, -550-nLaufendeNr*80, m_strPreis); //dcPrint.TextOut(1630, -550-nLaufendeNr*80, m_strVerfuegbar); } // Seite auswerfen dcPrint.EndPage(); // Dokument schließen dcPrint.EndDoc(); // Druckergerätekontext löschen dcPrint.DeleteDC(); MessageBox("Daten wurden erfolgreich gedruckt", "Info", MB_ICONEXCLAMATION); } else MessageBox("Fehler! Dokument konnte nicht gedruckt werden", "Fehler!", MB_ICONEXCLAMATION); }/// ende
-
Nimm doch einfach die Draw Funktion der CImageList die du verwendest um die Bilder in die Liste zu kriegen um das Bild zu zeichnen.
-
Das ist eine Antwort auf meine Frage(oben) das ich in einem anderen Forum bekommen habe! Ich hatte seher viel Zeit gebraucht um diese Lösung zu kriegen. Deswegen poste ich den Antwort von "Dings" um wetere Mitglieder die Suche zu erleihtern.
Es wäre vielleicht auch möglich, Text statt der Icons auszugeben (eben jeweils ein Wort für jeden Status). Jedenfalls könntest Du eine etwas ausgefeiltere Druckroutine verwenden. Wo Du gerade CodeProject erwähnst ... wie wäre es damit:
http://www.codeproject.com/listctrl/listprintdemo.asp
- listdemoviewprint.cpp und listdemoviewprint.h Deinem Projekt hinzufügen
- In listdemoviewprint.h über der Klassendefinition noch 'class CListView;' einfügen.
- listdemoviewprint.h in Deine Dialog-Sourcedatei einbinden
- Entferne die Variable m_pListView, die entsprechenden ASSERTs und die Methode SetListView aus der Klasse CListDemoViewPrint.
Optional kannst Du die Klasse natürlich auch umbenennen.Dann fügst Du noch "#include "listdemoviewprint.h"" und eine Druckfunktion ein. Beispiel (nur etwas angepasst):
BOOL DeinDialog::PrintList() { CPrintDialog dlg(FALSE); CPrintInfo pInfo; CListDemoViewPrint m_print; if (AfxGetApp()->DoPrintDialog(&dlg)) { HDC hdcPrinter = dlg.GetPrinterDC(); if (hdcPrinter == NULL) { // // Ist auch NULL, wenn der Vorgang abgebrochen wird } else { CDC dcPrinter; dcPrinter.Attach(hdcPrinter); dcPrinter.m_bPrinting = TRUE; CString Str; m_print.SetDocTitle(_T("Titel")); // m_print.SetAppName(_T("AppName")); DOCINFO docinfo; memset(&docinfo, 0, sizeof(docinfo)); docinfo.cbSize = sizeof(docinfo); docinfo.lpszDocName = _T(""); if (dcPrinter.StartDoc(&docinfo) < 0) { AfxMessageBox(_T("Fehler beim Drucken aufgetreten.")); } else { m_print.SetListCtrl(&m_List); m_print.OnPreparePrinting(&pInfo); m_print.OnBeginPrinting(&dcPrinter, &pInfo); for (unsigned int i=1; i<=p Info.GetMaxPage(); i++) { dcPrinter.StartPage(); pInfo.m_nCurPage = i; m_print.OnPrint(&dcPrinter, &pInfo); dcPrinter.EndPage(); } m_print.OnEndPrinting(&dcPrinter, &pInfo); dcPrinter.EndDoc(); } } } return TRUE; }
Natürlich solltest Du zumindest noch die Fehlermeldungen anpassen bzw. Ressourcen-Strings verwenden.
Wenn Du die Anzahl der Zeilen begrenzen willst, kannst Du das in PrintList bzw. CListDemoViewPrint::PrintBody tun.Deine Spalten, in denen auf dem Bildschirm Icons gezeigt werden, sind trotzdem noch leer ...
Das liegt eben daran, dass a) sich kein Text darin befindet und b) Du (genau wie in CListDemoViewPrint::DrawRow) ja Text ausgibst und keine Icons - wie Du ja selbst schon geschrieben hast.Bei Dir:
m_strProdukt = m_cList.GetItemText(i, 0); m_strHersteller = m_cList.GetItemText(i, 1); m_strPreis = m_cList.GetItemText(i, 2); m_strVerfuegbar = m_cList.GetItemText(i, 3); // und ausgeben dcPrint.TextOut(80, -550-nLaufendeNr*80, m_strProdukt); // Hmm ...
und in CListDemoViewPrint::DrawRow
for (int nCol = 0; nCol < m_nPageCols; nCol++) { CRect rect = GetCellRect(nRow,nCol); CString strText = m_pListCtrl->GetItemText(nRow, m_nColumns[nCol]); DrawText(pDC->m_hDC, strText, -1, rect, DT_LEFT | DT_VCENTER); }
Wenn Du nun Wörter statt der Icons ausgeben willst, musst Du nur den Subitems jeweils Text zuweisen. Dieser wird ja nicht auf dem Bildschirm ausgegeben (in der Custom-Draw Methode), kann aber trotzdem beim Drucken abgerufen werden.
Also z.B. statt
Zitatm_List.SetItem(idx, 3, LVIF_IMAGE, NULL, 2, 0, 0, 0);
m_List.SetItem(idx, 3, LVIF_IMAGE | LVIF_TEXT, DeinStatusString, 2, 0, 0, 0);
Ok, Du willst Icons ... Vorschlag: Da es mit Icons beim Drucken Probleme geben kann (skalieren ...) - teilweise auch abhängig von der Windows-Version - zeichnest Du direkt farbige, gefüllte Kreise. Die können auch noch gleich einen dunklen Umriss haben, was gerade bei der gelben Farbe auf dem Papier sinnvoll wäre.
Aber zuerst müssen die Header zentriert sein. Ersetze in CListDemoViewPrint::PrintBody
for (int i = 0; i < m_nPageCols; i++) { DrawText(pDC->m_hDC, GetColumnHeading(i), -1, GetColumnRect(i), DT_LEFT | DT_VCENTER);
durch
for (int i = 0; i < m_nPageCols; i++) { CRect colRect = GetColumnRect(i); if(i > 0) { // Anpassen! // Column-Header-Text zentrieren CSize txtSize = pDC->GetTextExtent(GetColumnHeading(i)); colRect.left = colRect.left + colRect.Width() / 2 - txtSize.cx / 2; } DrawText(pDC->m_hDC, GetColumnHeading(i), -1, colRect, DT_LEFT | DT_VCENTER); }
Neue CListDemoViewPrint-Membervariablen:
CBrush m_brushGreen, m_brushYellow, m_brushRed;
In den Konstruktor von CListDemoViewPrint (Farben anpassen):
m_brushGreen.CreateSolidBrush(RGB(0, 255, 0)); m_brushYellow.CreateSolidBrush(RGB(255, 255, 0)); m_brushRed.CreateSolidBrush(RGB(255, 0, 0));
In den Dekonstruktor:
m_brushGreen.DeleteObject(); m_brushYellow.DeleteObject(); m_brushRed.DeleteObject();
CListDemoViewPrint::DrawRow: Bei Items mit zugeordnetem Icon wird zentriert ein entsprechender Kreis gezeichnet.
In der ImageList müssen die Icons 0=grün, 1=gelb und 2=rot sein, damit es so passt.
Man könnte natürlich auch die Indizes der Spalten, in denen die "Icons" gezeichnet werden sollen, dem Konstruktor übergeben und in einer Membervariable speichern (in einem Array z.B.). Oder auch die Zuordnung "Image Index <-> Farbe". Ähnliches gilt für CListDemoViewPrint::PrintBody; dort wird einfach jeder Header-String > 0 zentriert. Das kannst Du ja selbst ändern, wie Du möchtest; hier geht es nur ums Prinzip. BTW: Du kannst auch noch Linien zeichnen, wenn Du willst.void CListDemoViewPrint::DrawRow(CDC* pDC, int nRow) { ASSERT(m_pListCtrl); for (int nCol = 0; nCol < m_nPageCols; nCol++) { CRect rect = GetCellRect(nRow, nCol); CString strText = m_pListCtrl->GetItemText(nRow, m_nColumns[nCol]); DrawText(pDC->m_hDC, strText, -1, rect, DT_LEFT | DT_VCENTER); CImageList* pImgList = m_pListCtrl->GetImageList(LVSIL_SMALL); if(pImgList != NULL) { LVITEM item; ZeroMemory(&item, sizeof(LVITEM)); item.iItem = nRow; item.iSubItem = m_nColumns[nCol]; item.mask = LVIF_IMAGE; m_pListCtrl->GetItem(&item); CBrush *oldBrush; switch(item.iImage) { case 0: oldBrush = pDC->SelectObject(&m_brushGreen); break; case 1: oldBrush = pDC->SelectObject(&m_brushYellow); break; case 2: oldBrush = pDC->SelectObject(&m_brushRed); break; default: continue; } const int spFrac = 6; int tbSpace = rect.Height()/spFrac; int radius = rect.Height()/2 - tbSpace; int topLeftX = rect.left + rect.Width()/2 - radius; int topLeftY = rect.top + tbSpace; int bottomRightX = topLeftX + 2*radius; int bottomRightY = rect.bottom - tbSpace; pDC->Ellipse(topLeftX, topLeftY, bottomRightX, bottomRightY); pDC->SelectObject(oldBrush); } } }