Александр (sandy) Илюшенко любезно предоставил статью о кастомизации класса для печати отчетов wxHtmlEasyPrinting:
В этой статье я опишу еще один переопределенный класс для своих нужд. Думаю, что не только для моих нужд. Началось все с того, что мне пришлось выводить нокоторые свои данные на печать в табличном представлении. Но перед этим, как сами понимаете, не лишним будет и предварительный просмотр.
Для реализации этой простой задачи мне приглянулся класс wxHtmlEasyPrinting, которому дастаточно передать строку, содержащую html-код. Вот небольшой пример его использования.
Example1.cpp
#include <wx/html/htmprint.h> /*... */ wxHtmlEasyPrinting* prn = new wxHtmlEasyPrinting(wxT("Довідник користувачів")); prn->GetPrintData()->SetOrientation(wxLANDSCAPE); prn->GetPageSetupData()->SetMarginTopLeft(wxPoint(10,10)); prn->GetPageSetupData()->SetMarginBottomRight(wxPoint(5,5)); prn->SetFooter(sFooter); prn->PreviewText(sText); /*... */
Для пояснения: sFooter – это строка, содержащая html-код нижнего колонтитула; sText – строка, содержащая html-код содержания документа, выводимого на печать.
Выглядит все это довольно неплохо:
Но мне, как всегда нашлось что-то, что не понравилось. Первое, что мне захотелось улучшить, – это кнопки навигации. Второе, – мне (вернее пользователю) нужно было все написать “на родном языке”. Чтобы долго не рассказывать, посмотрите на рисунок ниже, и ощутите разницу.
Теперь, как это мне удалось. Для начала, посмотрите на заголовочный файл.
wxHtmlPrint.h
#pragma once #include <wx/html/htmprint.h> #include <wx/choice.h> #include <wx/numdlg.h> #include <wx/bmpbuttn.h> #include <wx/sizer.h> class wxPreviewCtrlBar : public wxPreviewControlBar { wxBitmapButton* m_bPrint; wxBitmapButton* m_bRewind; wxBitmapButton* m_bPreview; wxBitmapButton* m_bNext; wxBitmapButton* m_bLast; public: wxPreviewCtrlBar(wxPrintPreviewBase* preview, long buttons, wxWindow* parent, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxTAB_TRAVERSAL, const wxString& name = wxT("panel")); void CreateButtons(); void OnGoto(); }; class wxPreviewCtrl : public wxPreviewFrame { wxPreviewCtrlBar* m_ctrlBar; public: wxPreviewCtrl(wxPrintPreviewBase* preview, wxWindow* parent, const wxString& title = wxT("Print Preview"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_FRAME_STYLE, const wxString& name = wxT("frame")); inline wxPreviewControlBar* GetControlBar() const {return (wxPreviewControlBar*)m_ctrlBar;} void Initialize(); void CreateControlBar(); }; class wxHtmlPrint : public wxHtmlEasyPrinting { wxString m_sTitle; wxWindow* m_wParent; protected: bool DoPreview(wxHtmlPrintout* printout1, wxHtmlPrintout* printout2); public: wxHtmlPrint::wxHtmlPrint(const wxString& name, wxWindow* parentWindow = NULL); };
Как видите, переопределить пришлось не один класс. а целых три. Теперь, по-порядку. Класс wxPreviewCtrlBar
, наследуемый от wxPreviewControlBar
нужен больше всего, так как именно в этом классе переопределены кнопки и их названия. Подробнее, вместо wxButton
для навигации используются wxBitmapButton
, а для кнопки “Close” написано “Закрити”. (Интерфейс программы был написан на украинском языке. Кому необходимо, – перепишите по-русски сами) Для реализации этой задачи и нужно было переписать функцию CreateButtons()
. Функция OnGoto()
переписана для того, чтобы в функцию wxGetNumberFromUser
передать строки на украинском языке, а не на английском.
Класс wxPreviewCtrl
, наследуемый от wxPreviewFrame
, имеет член экземпляра wxPreviewCtrlBar* m_ctrlBar
. Его предок использовал предка этого члена. Потому пришлось переписать функции, в которых использовался wxPreviewControlBar
, почти полностью, изменив лишь использование wxPreviewControlBar*
на wxPreviewCtrlBar*
.
В классе wxHtmlPrint
, наследнике wxHtmlEasyPrinting
, надо было переопределить только функцию DoPreview
. Но, так как члены предка wxWindow* m_ParentWindow
и wxString m_Name
– закрытые, то пришлось ввести их альтернативы: wxWindow* m_wParent
и wxString m_sTitle
.
wxHtmlPrint.cpp
#include "wxHtmlPrint.h" /// XPM static char * btn_rew_xpm[] = { "16 16 2 1", " c None", ". c #000000", " ", " .. . ", " .. .. ", " .. ... ", " .. .... ", " .. ..... ", " .. ...... ", " .. ....... ", " .. ....... ", " .. ...... ", " .. ..... ", " .. .... ", " .. ... ", " .. .. ", " .. . ", " "}; static char * btn_prev_xpm[] = { "16 16 2 1", " c None", ". c #000000", " ", " . . ", " .. .. ", " ... ... ", " .... .... ", " ..... ..... ", " ...... ...... ", " .............. ", " .............. ", " ...... ...... ", " ..... ..... ", " .... .... ", " ... ... ", " .. .. ", " . . ", " "}; static char * btn_next_xpm[] = { "16 16 2 1", " c None", ". c #000000", " ", " . . ", " .. .. ", " ... ... ", " .... .... ", " ..... ..... ", " ...... ...... ", " .............. ", " .............. ", " ...... ...... ", " ..... ..... ", " .... .... ", " ... ... ", " .. .. ", " . . ", " "}; static char * btn_last_xpm[] = { "16 16 2 1", " c None", ". c #000000", " ", " . .. ", " .. .. ", " ... .. ", " .... .. ", " ..... .. ", " ...... .. ", " ....... .. ", " ....... .. ", " ...... .. ", " ..... .. ", " .... .. ", " ... .. ", " .. .. ", " . .. ", " "}; static char *print_xpm[] = { /* columns rows colors chars-per-pixel */ "16 15 39 1", "< c #E3E4E6", "+ c #C3C3C4", "i c #FFFFFF", ": c #74879B", "# c #5A89A6", "a c #F1F4F7", "r c #5A809C", "@ c #BDCCD9", "e c #7A92A4", "% c #3F6F93", "t c #9FA2A6", "3 c #939495", "w c #5F666D", "9 c #65839E", "5 c #4A7291", "$ c #4B7F9E", " c None", "O c #DFE0E2", "o c #F3F3F3", "; c #84A5BB", "& c #467291", ". c #7897AD", "* c #407598", "4 c #CFCFD0", "7 c #6F90A6", "y c #6A89A2", "0 c #AAADB2", "1 c #D2D3D4", "u c #4F7592", ", c #BCBDBE", "p c #57778E", "q c #979BA0", "2 c #ABABAC", "- c #E7E7E7", "= c #D6DEE6", "> c #9FA0A0", "8 c #829EB5", "X c #8FB0C3", "6 c #5D7C93", /* pixels */ " .XXXXXXXX ", " .oooooooX ", " .OOOOOOOX ", " .+++++++X ", "@##$%&&&&&%*##@ ", "$=-;:>,<123$-=$ ", ".44.5678.96$44. ", "7,,,,,,,,,,,,,7 ", "900qwwwwwwwe009 ", "rtt9ryyyyyyuttr ", "6qq6iiiiiii%qq6 ", "633paiiiiii%336 ", "XXX*iiiiiii%XXX ", " 6iiiiiii% ", " $XXXXXXX# " }; /// wxPreviewCtrlBar wxPreviewCtrlBar::wxPreviewCtrlBar(wxPrintPreviewBase* preview, long buttons, wxWindow* parent, const wxPoint& pos, const wxSize& size, long style, const wxString& name) : wxPreviewControlBar(preview, buttons, parent, pos, size, style, name) { m_bPrint = (wxBitmapButton*)NULL; m_bRewind = (wxBitmapButton*)NULL; m_bPreview = (wxBitmapButton*)NULL; m_bNext = (wxBitmapButton*)NULL; m_bLast = (wxBitmapButton*)NULL; } void wxPreviewCtrlBar::CreateButtons() { SetSize(0, 0, 400, 40); wxBoxSizer *item0 = new wxBoxSizer( wxHORIZONTAL ); m_closeButton = new wxButton(this, wxID_PREVIEW_CLOSE, wxT("Закрити"), wxDefaultPosition, wxDefaultSize, 0); item0->Add(m_closeButton, 0, wxALIGN_CENTRE | wxALL, 5); if (m_buttonFlags & wxPREVIEW_PRINT) { m_bPrint = new wxBitmapButton(this, wxID_PREVIEW_PRINT, wxBitmap(print_xpm), wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW); item0->Add(m_bPrint, 0, wxALIGN_CENTRE|wxALL, 5); } // Exact-fit buttons are too tiny on wxUniversal int navButtonStyle; wxSize navButtonSize; #ifdef __WXUNIVERSAL__ navButtonStyle = 0; navButtonSize = wxSize(40, m_closeButton->GetSize().y); #else navButtonStyle = wxBU_EXACTFIT; navButtonSize = wxDefaultSize; #endif if (m_buttonFlags & wxPREVIEW_FIRST) { m_bRewind = new wxBitmapButton(this, wxID_PREVIEW_FIRST, wxBitmap(btn_rew_xpm), wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW); item0->Add(m_bRewind, 0, wxALIGN_CENTRE | wxALL, 5); } if (m_buttonFlags & wxPREVIEW_PREVIOUS) { m_bPreview = new wxBitmapButton(this, wxID_PREVIEW_PREVIOUS, wxBitmap(btn_prev_xpm), wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW); item0->Add(m_bPreview, 0, wxALIGN_CENTRE |wxRIGHT | wxTOP | wxBOTTOM, 5); } if (m_buttonFlags & wxPREVIEW_NEXT) { m_bNext = new wxBitmapButton(this, wxID_PREVIEW_NEXT, wxBitmap(btn_next_xpm), wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW); item0->Add(m_bNext, 0, wxALIGN_CENTRE | wxRIGHT | wxTOP | wxBOTTOM, 5); } if (m_buttonFlags & wxPREVIEW_LAST) { m_bLast = new wxBitmapButton(this, wxID_PREVIEW_LAST, wxBitmap(btn_last_xpm), wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW); item0->Add(m_bLast, 0, wxALIGN_CENTRE | wxRIGHT | wxTOP | wxBOTTOM, 5); } if (m_buttonFlags & wxPREVIEW_GOTO) { m_gotoPageButton = new wxButton(this, wxID_PREVIEW_GOTO, wxT("Сторінка..."), wxDefaultPosition, wxDefaultSize, 0); item0->Add(m_gotoPageButton, 0, wxALIGN_CENTRE | wxALL, 5); } if (m_buttonFlags & wxPREVIEW_ZOOM) { wxString choices[] = { wxT("10%"), wxT("15%"), wxT("20%"), wxT("25%"), wxT("30%"), wxT("35%"), wxT("40%"), wxT("45%"), wxT("50%"), wxT("55%"), wxT("60%"), wxT("65%"), wxT("70%"), wxT("75%"), wxT("80%"), wxT("85%"), wxT("90%"), wxT("95%"), wxT("100%"), wxT("110%"), wxT("120%"), wxT("150%"), wxT("200%")}; int n = WXSIZEOF(choices); m_zoomControl = new wxChoice(this, wxID_PREVIEW_ZOOM, wxDefaultPosition, wxSize(70,wxDefaultCoord), n, choices, 0); item0->Add(m_zoomControl, 0, wxALIGN_CENTRE | wxALL, 5); SetZoomControl(m_printPreview->GetZoom()); } SetSizer(item0); item0->Fit(this); } void wxPreviewCtrlBar::OnGoto() { wxPrintPreviewBase *preview = GetPrintPreview(); long nPage=0; if (preview) { if (preview->GetMinPage() > 0) { nPage=wxGetNumberFromUser( wxString::Format("Введіть номер сторінки між %d та %d:", preview->GetMinPage(),preview->GetMaxPage()), wxString::Format("%d",preview->GetCurrentPage()), wxT("Перейти на сторінку"), preview->GetCurrentPage()); if (preview->GetPrintout()->HasPage(nPage)) { preview->SetCurrentPage(nPage); } } } } /// wxPreviewCtrl wxPreviewCtrl::wxPreviewCtrl(wxPrintPreviewBase* preview, wxWindow* parent, const wxString& title, const wxPoint& pos, const wxSize& size, long style, const wxString& name) : wxPreviewFrame(preview, parent, title, pos, size, style, name) { m_ctrlBar = NULL; } void wxPreviewCtrl::Initialize() { #if wxUSE_STATUSBAR CreateStatusBar(); #endif CreateCanvas(); CreateControlBar(); m_printPreview->SetCanvas(m_previewCanvas); m_printPreview->SetFrame(this); wxBoxSizer *item0 = new wxBoxSizer( wxVERTICAL ); item0->Add(m_ctrlBar, 0, wxGROW | wxALIGN_CENTER_VERTICAL, 5); item0->Add(m_previewCanvas, 1, wxGROW | wxALIGN_CENTER_VERTICAL, 5); SetAutoLayout( true ); SetSizer( item0 ); m_windowDisabler = new wxWindowDisabler(this); Layout(); m_printPreview->AdjustScrollbars(m_previewCanvas); m_previewCanvas->SetFocus(); m_ctrlBar->SetFocus(); } void wxPreviewCtrl::CreateControlBar() { long buttons = wxPREVIEW_DEFAULT; if (m_printPreview->GetPrintoutForPrinting()) buttons |= wxPREVIEW_PRINT; m_ctrlBar = new wxPreviewCtrlBar(m_printPreview, buttons, this, wxPoint(0,0), wxSize(400,40)); m_ctrlBar->CreateButtons(); } /// wxHtmlPrint wxHtmlPrint::wxHtmlPrint(const wxString& name, wxWindow* parentWindow) : wxHtmlEasyPrinting(name, parentWindow), m_sTitle(name), m_wParent(parentWindow) { } bool wxHtmlPrint::DoPreview(wxHtmlPrintout* printout1, wxHtmlPrintout* printout2) { wxPrintDialogData printDialogData(*GetPrintData()); wxPrintPreview *preview = new wxPrintPreview(printout1, printout2, &printDialogData); if (!preview->Ok()) { delete preview; return false; } wxPreviewCtrl* frame = new wxPreviewCtrl(preview, m_wParent, m_sTitle + wxT(" (Попередній перегляд)"), wxPoint(100, 100), wxSize(650, 500)); frame->Centre(wxBOTH); frame->Initialize(); frame->Show(true); return true; }
Теперь, для красивого предварительного просмотра, Вы можете использовать wxHtmlPrint. Использование аналогично его предку – wxHtmlEasyPrinting.
Example2.cpp
#include <wxHtmlPrint.h> /* ... */ wxHtmlPrint* prn = new wxHtmlPrint(wxT("Довідник користувачів")); prn->GetPrintData()->SetOrientation(wxLANDSCAPE); prn->GetPageSetupData()->SetMarginTopLeft(wxPoint(10,10)); prn->GetPageSetupData()->SetMarginBottomRight(wxPoint(5,5)); prn->SetFooter(sFooter); /// Предварительный просмотр prn->PreviewText(sText); /// Печать без предварительного просмотра prn->PrintText(sText); /* ... */
2 Comments
T-Rex
ИМХО, конечно, но локализацию можно было бы сделать стандартными средствами wxWidgets или с помощью wxTranslationHelper
Sandy
Так тебе и карты в руки. Мне, если честно, некогда было, надо было побыстрее, а приложение было не многоязычным