#include #include "wx/wx.h" #include "wx/print.h" #include "wx/printdlg.h" #include static const int brush_size = 3; /** * Shows a basic example of how to print stuff in wx. */ class QuickPrint : public wxPrintout { wxPageSetupDialogData m_page_setup; /** the type of paper (letter, A4, etc...) */ wxPaperSize m_paper_type; /** horizontal or vertical */ int m_orient; // Or, if you use wxWidgets 2.9+ : // wxPrintOrientation m_orient; /** number of pages we want to print. here it's static, but in a real example you will often * want to calculate dynamically once you know the size of the printable area from page setup */ int m_page_amount; /** margins, in millimeters */ int m_margin_left, m_margin_right, m_margin_top, m_margin_bottom; /** we'll use this to determine the coordinate system; it describes the number of units per * centimeter (i.e. how fine the coordinate system is) */ float m_units_per_cm; /** will contain the dimensions of the coordinate system, once it's calculated. * in the printing callback, you can then draw from (0, 0) to (m_coord_system_width, m_coord_system_height), * which will be the area covering the paper minus the margins */ int m_coord_system_width, m_coord_system_height; public: /** * @param page_amount number of pages we want to print. Here it's static because it's just a test, but in * real code you will often want to calculate dynamically once you know the size of the * printable area from page setup * @param title name of the print job / of the printed document * @param units_per_cem we'll use this to determine the coordinate system; it describes the number of units * per centimeter (i.e. how fine the coordinate system is) */ QuickPrint(int page_amount, wxString title, float units_per_cm) : wxPrintout( title ) { m_page_amount = page_amount; m_orient = wxPORTRAIT; // wxPORTRAIT, wxLANDSCAPE m_paper_type = wxPAPER_LETTER; m_margin_left = 16; m_margin_right = 16; m_margin_top = 32; m_margin_bottom = 32; m_units_per_cm = units_per_cm; } /** shows the page setup dialog, OR sets up defaults */ bool performPageSetup(const bool showPageSetupDialog) { // don't show page setup dialog, use default values wxPrintData printdata; printdata.SetPrintMode( wxPRINT_MODE_PRINTER ); printdata.SetOrientation( m_orient ); printdata.SetNoCopies(1); C printdata.SetPaperId( m_paper_type ); m_page_setup = wxPageSetupDialogData(printdata); m_page_setup.SetMarginTopLeft (wxPoint(m_margin_left, m_margin_top)); m_page_setup.SetMarginBottomRight(wxPoint(m_margin_right, m_margin_bottom)); if (showPageSetupDialog) { wxPageSetupDialog dialog( NULL, &m_page_setup ); if (dialog.ShowModal() == wxID_OK) { m_page_setup = dialog.GetPageSetupData(); m_orient = m_page_setup.GetPrintData().GetOrientation(); m_paper_type = m_page_setup.GetPrintData().GetPaperId(); wxPoint marginTopLeft = m_page_setup.GetMarginTopLeft(); wxPoint marginBottomRight = m_page_setup.GetMarginBottomRight(); m_margin_left = marginTopLeft.x; m_margin_right = marginBottomRight.x; m_margin_top = marginTopLeft.y; m_margin_bottom = marginBottomRight.y; } else { std::cout << "user canceled at first dialog" << std::endl; return false; } } return true; } /** Called when printing starts */ void OnBeginPrinting() { // set-up coordinate system however we want, we'll use it when drawing // take paper size and margin sizes into account when setting up coordinate system // so that units are "square" (1 unit x is a wide as 1 unit y is high) // (actually, if we don't make it square, on some platforms wx will even resize your // margins to make it so) wxSize paperSize = m_page_setup.GetPaperSize(); // in millimeters // still in millimeters float large_side = std::max(paperSize.GetWidth(), paperSize.GetHeight()); float small_side = std::min(paperSize.GetWidth(), paperSize.GetHeight()); float large_side_cm = large_side / 10.0f; // in centimeters float small_side_cm = small_side / 10.0f; // in centimeters if (m_orient == wxPORTRAIT) { float ratio = float(large_side - m_margin_top - m_margin_bottom) / float(small_side - m_margin_left - m_margin_right); m_coord_system_width = (int)((small_side_cm - m_margin_left/10.f - m_margin_right/10.0f)*m_units_per_cm); m_coord_system_height = m_coord_system_width*ratio; } else { float ratio = float(large_side - m_margin_left - m_margin_right) / float(small_side - m_margin_top - m_margin_bottom); m_coord_system_height = (int)((small_side_cm - m_margin_top/10.0f - m_margin_bottom/10.0f)* m_units_per_cm); m_coord_system_width = m_coord_system_height*ratio; } } /** returns the data obtained from the page setup dialog (or the defaults, * if dialog was not shown) */ wxPrintData getPrintData() { return m_page_setup.GetPrintData(); } /** Called when starting to print a document */ bool OnBeginDocument(int startPage, int endPage) { std::cout << "beginning to print document, from page " << startPage << " to " << endPage << std::endl; return wxPrintout::OnBeginDocument(startPage, endPage); } /** wx will call this to know how many pages can be printed */ void GetPageInfo(int *minPage, int *maxPage, int *pageSelFrom, int *pageSelTo) { *minPage = 1; *maxPage = m_page_amount; *pageSelFrom = 1; *pageSelTo = m_page_amount; } /** called by wx to know what pages this document has */ bool HasPage(int pageNum) { // wx will call this to know how many pages can be printed return pageNum >= 1 && pageNum <= m_page_amount; } /** called by wx everytime it's time to render a specific page onto the * printing device context */ bool OnPrintPage(int pageNum) { std::cout << "printing page " << pageNum << std::endl; // ---- setup DC with coordinate system ---- FitThisSizeToPageMargins(wxSize(m_coord_system_width, m_coord_system_height), m_page_setup); wxRect fitRect = GetLogicalPageMarginsRect(m_page_setup); wxCoord xoff = (fitRect.width - m_coord_system_width) / 2; wxCoord yoff = (fitRect.height - m_coord_system_height) / 2; OffsetLogicalOrigin(xoff, yoff); wxDC* ptr = GetDC(); if (ptr==NULL || !ptr->IsOk()) { std::cout << "DC is not Ok, interrupting printing" << std::endl; return false; } wxDC& dc = *ptr; // ---- A couple helper variables to help us during draw within paper area ----- const int x0 = 0; const int y0 = 0; const int width = m_coord_system_width; const int height = m_coord_system_height; const int x1 = x0 + width; const int y1 = y0 + height; const int center_x = x0 + width/2; const int center_y = y0 + height/2; std::cout << "printable area : (" << x0 << ", " << y0 << ") to (" << x1 << ", " << y1 << ")" << std::endl; // ---- Draw to the print DC ---- dc.Clear(); dc.SetPen( wxPen( wxColour(0,0,0), brush_size ) ); dc.SetBrush( *wxTRANSPARENT_BRUSH ); // draw a rectangle to show its bounds. dc.DrawRectangle(x0, y0, width, height); // draw wxWidgets logo dc.SetBrush( *wxRED_BRUSH ); dc.DrawRectangle(center_x-45-38, center_y, 76, 76); dc.SetBrush( *wxBLUE_BRUSH ); dc.DrawRectangle(center_x-38, center_y-45, 76, 76); dc.SetBrush( wxBrush( wxColor(255,244,0) ) ); dc.DrawRectangle(center_x+45-38, center_y-10, 76, 76); // draw page number label wxString label( wxT("This is page #") ); label << pageNum; dc.SetTextBackground( wxColour(255,255,0) ); dc.SetTextForeground( wxColour(0,0,0) ); dc.DrawText( label, x0 + width/5, y0 + height - 50 ); return true; } /** Called when printing is done. I have nothing to do in this case * in this example. */ void OnEndPrinting() { } }; // ------------------------------------------------------------------------------------- // HOW TO INVOKE THIS TEST // ------------------------------------------------------------------------------------- class MyApp: public wxApp { public: virtual bool OnInit(); }; IMPLEMENT_APP(MyApp) bool MyApp::OnInit() { QuickPrint* myprint = new QuickPrint( 5 /* 5 pages */, wxT("wxPrint test"), 30 /* 30 units per centimeter */ ); if (!myprint->performPageSetup(true)) { // user cancelled exit(0); } wxPrintDialogData data(myprint->getPrintData()); wxPrinter printer(&data); const bool success = printer.Print(NULL, myprint, true /* show dialog */); delete myprint; if (!success) { std::cerr << "Failed!!\n"; return false; } exit(0); return true; }