В этой статье я опишу еще один переопределенный класс для своих нужд. Думаю, что не только для моих нужд. Началось все с того, что мне пришлось выводить нокоторые свои данные на печать в табличном представлении. Но перед этим, как сами понимаете, не лишним будет и предварительный просмотр.
Для реализации этой простой задачи мне приглянулся класс 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);
/* ... */