[c++]代码库
#include <iostream>
#include "wx/wx.h"
#include "wx/print.h"
#include "wx/printdlg.h"
#include <cmath>
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;
}