Categories: wxWidgets

Кастомизация класса wxHtmlEasyPrinting для печати отчетов в wxWidgets

Александр (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);
 /* ... */
T-Rex

View Comments

  • ИМХО, конечно, но локализацию можно было бы сделать стандартными средствами wxWidgets или с помощью wxTranslationHelper

  • Так тебе и карты в руки. Мне, если честно, некогда было, надо было побыстрее, а приложение было не многоязычным

Share
Published by
T-Rex

Recent Posts

Разработка кроссплатформенных модульных приложений на C++ с библиотекой wxWidgets

Введение Уже долгое время не пишу статьи о разработке, хотя сам процесс написания мне очень…

10 years ago

wxWidgets App With Plugins (Windows/Linux/Mac) – Sample Source Code

I can see that there is still a lot of topics at wxWidgets forums related…

11 years ago

wxToolBox is Now Open-Source!

I've just published the source code of wxToolBox component and a couple of sample apps at…

11 years ago

Microsoft Kinect Helper Library and Sample for wxWidgets

Microsoft released their Kinect SDK several days ago. So, for those wxWidgets developers who are…

13 years ago

wxJSON 1.1.0 Released

JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to…

14 years ago

wxRuby. Оно даже работает!

Вдохновленнный читаемой нынче книгой My Job Went to India: 52 Ways to Save Your Job…

15 years ago