Probleme mit Print Preview für mehrere Seiten.
-
Ich habe im Internet folgenden Code für ein Print Preview gefunden, was auch super funktioniert, jedoch nur für die eine Seite, die ich in der Variablen "currPage" angebe. Ich hätte gerne eine "Next"-Button, der dann die nächste Seite anzeigt, aber was auch immer ich probiert habe, es tut sich nichts. Hat jemand vielleicht eine Lösung für mich? Danke im Voraus.
MfG Anika
(Ich weiß, der Code ist ein bisschen lang, aber ich bin mir nicht sicher, wieviel man wissen muss um mein Problem lösen zu können und es sind auch noch viele Kommentare drin.)//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit2.h" #include "Unit1.h" //--------------------------------------------------------------------------- #include <vcl\printers.hpp> #include <vector> // for stl typedef struct tagTPageOffset { long int Start; long int End; RECT rendRect; } TPageOffsets; //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TPreviewForm *PreviewForm; class TPreviewPanel : public TPanel { public: __fastcall virtual TPreviewPanel(Classes::TComponent* AOwner) : TPanel(AOwner) { }; __fastcall virtual ~TPreviewPanel(void) { }; __fastcall virtual void Paint(void) { TPanel::Paint(); PreviewForm->DrawRichEdit(); }; __property Canvas; }; //--------------------------------------------------------------------------- __fastcall TPreviewForm::TPreviewForm(TComponent* Owner) : TForm(Owner) { PreviewPanel = new TPreviewPanel(this); PreviewPanel->Parent = this; PreviewPanel->Color = clWhite; } __fastcall TPreviewForm::~TPreviewForm(void) { if (PreviewPanel) delete PreviewPanel; } //--------------------------------------------------------------------------- void __fastcall TPreviewForm::FormResize(TObject *Sender) { // get the printer dimensions. int wPage = ::GetDeviceCaps(Printer()->Handle, PHYSICALWIDTH); int hPage = ::GetDeviceCaps(Printer()->Handle, PHYSICALHEIGHT); // get the client window dimensions. int wClient = ClientWidth; int hClient = ClientHeight; // initially adjust width to match height wClient = ::MulDiv(ClientHeight, wPage, hPage); // if that doesn't fit, then do it the other way if (wClient > ClientWidth) { wClient = ClientWidth; hClient = ::MulDiv(ClientWidth, hPage, wPage); // center the page in the window PreviewPanel->Top = (ClientHeight - hClient) >> 1; // divide by two } else // center the page in the window PreviewPanel->Left = (ClientWidth - wClient) >> 1; // divide by two // now set size of panel PreviewPanel->Width = wClient; PreviewPanel->Height = hClient; } //--------------------------------------------------------------------------- void TPreviewForm::DrawRichEdit(void) { int wPage = ::GetDeviceCaps(Printer()->Handle, PHYSICALWIDTH); int hPage = ::GetDeviceCaps(Printer()->Handle, PHYSICALHEIGHT); int xPPI = ::GetDeviceCaps(Printer()->Handle, LOGPIXELSX); int yPPI = ::GetDeviceCaps(Printer()->Handle, LOGPIXELSY); int wTwips = ::MulDiv(wPage, 1440, xPPI); int hTwips = ::MulDiv(hPage, 1440, yPPI); RECT pageRect; pageRect.left = pageRect.top = 0; pageRect.right = wTwips; pageRect.bottom = hTwips; RECT rendRect; rendRect.left = rendRect.top = -1440; rendRect.right = pageRect.right - 1440 * 3; rendRect.bottom = pageRect.bottom - 1440 * 3; std::vector<TPageOffsets> FPageOffsets; TPageOffsets po; po.Start = 0; //We will be using several device contexts (DCs), so let's go ahead and //create variables for them. HDC hdcDesktop = ::GetWindowDC(::GetDesktopWindow()); HDC hdcCanvas = dynamic_cast<TPreviewPanel*>(PreviewPanel)->Canvas->Handle; HDC hdcPrinter = Printer()->Handle; //Next, define and initialize a FORMATRANGE structure. TFormatRange fr; fr.hdc = hdcDesktop; fr.hdcTarget = hdcPrinter; fr.chrg.cpMin = po.Start; fr.chrg.cpMax = -1; //We will need the size of the text in the control. int lastOffset = ::SendMessage(Form1->re_edit->Handle, WM_GETTEXTLENGTH, 0, 0); //Clear the control's formatting buffer before rendering. ::SendMessage(Form1->re_edit->Handle, EM_FORMATRANGE, (WPARAM) 0, (LPARAM) 0); //Here is the tricky part. We need to scale the rendering DC to match the //size of the printed page in printer device units. ::SaveDC(hdcCanvas); ::SetMapMode(hdcCanvas, MM_TEXT); // set to device units ::SetMapMode(hdcCanvas, MM_ANISOTROPIC); // inherits prior mapping mode ::SetMapMode(hdcPrinter, MM_TEXT); // set to device units ::SetWindowExtEx(hdcCanvas, pageRect.right, pageRect.bottom, NULL); int xDesktopPPI = ::GetDeviceCaps(hdcDesktop, LOGPIXELSX); int yDesktopPPI = ::GetDeviceCaps(hdcDesktop, LOGPIXELSY); ::ScaleWindowExtEx(hdcCanvas, xDesktopPPI, 1440, yDesktopPPI, 1440, NULL); ::SetViewportExtEx(hdcCanvas, PreviewPanel->ClientWidth, PreviewPanel->ClientHeight, NULL); //Apparently, the Rich Edit control reduces the width of the rendering area //by the amount of the left offset to the printable portion of the page when //printing. This is a little odd to me because none of the Windows API GDI //functions care whether you are printing within the printable portion of the //page. Further, this occurs even though the rendering rectangle is already //within the printable portion of the page. Anyway, this does not seem to //happen when the rendering DC is the screen so we need to manually adjust //the rectangle ourselves. int xPrinterOffset = ::MulDiv(::GetDeviceCaps(hdcPrinter, PHYSICALOFFSETX), 1440, xPPI); int yPrinterOffset = ::MulDiv(::GetDeviceCaps(hdcPrinter, PHYSICALOFFSETY), 1440, yPPI); rendRect.left += xPrinterOffset >> 1; rendRect.right -= xPrinterOffset - (xPrinterOffset >> 1); rendRect.top += yPrinterOffset >> 1; rendRect.bottom -= yPrinterOffset - (yPrinterOffset >> 1); //Remember that we are hardcoding two-inch margins. int xOffset = ::MulDiv(PreviewPanel->ClientWidth << 1, 1440, pageRect.right); int yOffset = ::MulDiv(PreviewPanel->ClientHeight << 1, 1440, pageRect.bottom); ::SetViewportOrgEx(hdcCanvas, xOffset, yOffset, NULL); //Now we build the table of offsets. Note that we save the rendering //rectangle returned by the format call. When the rendering and target //devices are the same (or the target device is set to zero), the returned //rectangle is not really needed. In that case, you can simply ask the //control to print to the original rendering rectangle. However, when the //devices are different, the returned rendering rectangle is sometimes larger //than the requested rectangle. This must be a bug in the Rich Edit control. //We deal with it by saving the returned value to use when we actually render //the control to the screen. do { fr.rc = rendRect; fr.rcPage = pageRect; po.Start = fr.chrg.cpMin; fr.chrg.cpMin = ::SendMessage(Form1->re_edit->Handle, EM_FORMATRANGE, (WPARAM) 0, (LPARAM) &fr); po.End = fr.chrg.cpMin - 1; po.rendRect = fr.rc; FPageOffsets.push_back(po); } while (fr.chrg.cpMin != -1 && fr.chrg.cpMin < lastOffset); //If we were writing a fully working preview function, we could use //FPageOffsets.size() to determine how many pages had been formatted. We //would then set currPage (below) to the page that we wanted to display. In //this example, however, we are going to display only the first page. int currPage = 0; //Now we set the rendering device to the panel's canvas. Since we have not //cleared the formatting buffer, the target device is not needed, so we set //it to zero. Then we fill in the remaining parts of the FORMATRANGE //structure with the values we saved in FPageOffsets. Finally, we render the // text to the screen (WPARAM is non-zero). fr.hdc = hdcCanvas; fr.hdcTarget = 0; fr.rc = FPageOffsets[currPage].rendRect; fr.rcPage = pageRect; fr.chrg.cpMin = FPageOffsets[currPage].Start; fr.chrg.cpMax = FPageOffsets[currPage].End; fr.chrg.cpMin = ::SendMessage(Form1->re_edit->Handle, EM_FORMATRANGE, (WPARAM) 1, (LPARAM) &fr); //As I mentioned, the text may be drawn outside of the rendering rectangle. //To make that easier to see, let's draw a rectangle that shows where the //rendering rectangle should be. ::SetMapMode(hdcCanvas, MM_TEXT); ::SetViewportOrgEx(hdcCanvas, 0, 0, NULL); RECT frameRect = rendRect; OffsetRect(&frameRect, 1440 + 1440, 1440 + 1440); int xFactor = ::MulDiv(PreviewPanel->ClientWidth, (pageRect.right - rendRect.right) >> 1, pageRect.right); int yFactor = ::MulDiv(PreviewPanel->ClientHeight, (pageRect.bottom - rendRect.bottom) >> 1, pageRect.bottom); xFactor -=30; yFactor -= 30; frameRect.left = xFactor; frameRect.right = PreviewPanel->ClientWidth - xFactor; frameRect.top = yFactor; frameRect.bottom = PreviewPanel->ClientHeight - yFactor; ::FrameRect(hdcCanvas, &frameRect, ::GetStockObject(BLACK_BRUSH)); //To wrap up, we restore the panel's canvas to the original state, release //the desktop DC, clear the Rich Edit control's formatting buffer, empty the //page offset table, and close the DrawRichEdit() method. ::RestoreDC(hdcCanvas, -1); ::ReleaseDC(::GetDesktopWindow(), hdcDesktop); ::SendMessage(Form1->re_edit->Handle, EM_FORMATRANGE, (WPARAM) 0, (LPARAM) 0); FPageOffsets.erase(FPageOffsets.begin(), FPageOffsets.end()); }
-
Niky27 schrieb:
was auch immer ich probiert habe, es tut sich nichts.
Was zum Beispiel hast du denn probiert?
-
Ich habe einfach erstmal einen Button auf der PreviewForm eingefügt und versucht
PreviewForm->DrawRichEdit();
direkt auszuführe und "currPage" zu ändern, indem ich es als globale Variable definiert und erhöht oder auch currPage als Parameter der DrawRichEdit Funktion mitgegeben habe. Aber so einfach geht das wohl nicht.
Mir ist nicht ganz klar, wann diese Methode "Paint" aufgerufen wird. Bei MSDN stand irgendetwas von einer WM_PAINT Message, die man aber auch nicht selbst abschicken kann.
Wie kann ich also dieses DrawRichEdit() aufrufen und ein neues Rechteck zeichnen und füllen lassen und wann wird "Paint" aufgerufen" ???
MfG Anika
-
Weiß hier inzwischen irgendjemand eine Lösung oder braucht man mehr Angaben???
Bin nämlich noch kein Stück weiter.
-
Ja...ja...ich bin damit immer noch bwchäftigt. Wenn keiner eine Lösung weiß oder man mir auf Grund der Angaben nicht weiterhelfen kann, dann schreibt mir doch wenigstens DAS, dann weiß ich Bescheid und brauche auch nciht mehr gucken.
MfG Anika
-
Sollen jetzt alle 5000 mehr oder weniger regelmässigen Forumsbesucher hier reinschreiben, dass sie dir nicht helfen können!?
Aktivier einfach die Mail-Benachrichtigung (unten rechts), dann verpasst du keine eventuelle Antwort.
-
Ich weiß nicht, wie andere das empfinden, aber ich habe bei der doch nicht
ganz unbeträchtlichen Code-Menge sofort innerlich abgewunken.
Versuch doch erst mal selbst, Wesentliches von Unwesentlichem zu trennen.
Dann bist Du vielleicht sogar der Lösung schon ein Stück näher.Gruß,
Alexander