Tutorial 7 - Printing

This tutorial introduces printing with the "printer" program. The program consists of a window where the user can draw lines and a print button. When the user pushed the print button, the lines shown in the window are printed. This program is made up of five files - the source and header for the object that contains the window, the source and header for the printing widget and the source that contains the function main.

The PrintWidget object - PrintWidget.cc and PrintWidget.h

The object that implements printing is called PrintWidget and is derived from JXScrollableWidget

PrintWidget source file:

/******************************************************************************
 PrintWidget.cc

    BASE CLASS = JXWindowDirector

    Written by Glenn Bach - 1997.

 ******************************************************************************/

#include "PrintWidget.h"
#include <JXApplication.h>
#include <JXWidget.h>
#include <JXWindowPainter.h>
#include <JXDragPainter.h>
#include <JXColormap.h>
#include <jXGlobals.h>
#include <JPrinter.h>
#include <jAssert.h>

/******************************************************************************
 Constructor

 ******************************************************************************/

PrintWidget::PrintWidget
    (
    JXScrollbarSet*     scrollbarSet,
    JXContainer*        enclosure,
    const HSizingOption hSizing,
    const VSizingOption vSizing,
    const JCoordinate   x,
    const JCoordinate   y,
    const JCoordinate   w,
    const JCoordinate   h
    )
    :
    JXScrollableWidget(scrollbarSet, enclosure, hSizing, vSizing, x, y, w, h)
{
    // This changes our Bounds, independent of what part of us
    // is visible (our Frame).
    SetBounds(500, 400);

    // This array keeps track of the points that define the beginning and
    // ending of each line the is draw in the window.

    // See JCollection.h, JOrderedSet.h, and JArray.h for functionality

    itsPoints = new JArray<JPoint>();
    assert( itsPoints != NULL );
}

/******************************************************************************
 Destructor

 ******************************************************************************/

PrintWidget::~PrintWidget()
{
    // Unlike widgets, which are automatically deleted by the framework,
    // we must delete this JArray since it is a private instance variable.
    delete itsPoints;
}

/*****************************************************************************
 Print

 ******************************************************************************/

void
PrintWidget::Print
    (
    JPrinter& p
    )
{
    // Calculate the height needed for the header
    const JCoordinate headerHeight = p.JPainter::GetLineHeight();

    // Start the print document
    p.OpenDocument();

    // This will return false if the print job was cancelled
    if (p.NewPage())
        {
        // draw the header

        JRect pageRect = p.GetPageRect();
        p.String(pageRect.left, pageRect.top, "Printing Test",
                 pageRect.width(), JPainter::kHAlignCenter);
        p.LockHeader(headerHeight);

        // draw the page
        // Printing and drawing to the screen use the same code
        DrawStuff(p);

        // Finish the print job
        p.CloseDocument();
        }
}

/******************************************************************************
 Draw (virtual protected)

    This gets called by the event loop every time the Widget needs to
    be redrawn.

 ******************************************************************************/

void
PrintWidget::Draw
    (
    JXWindowPainter& p,
    const JRect& rect
    )
{
    // This needs to be out of the main drawing routing, because
    // we don't want this to print
    p.String(10, 10, "Type 'c' to clear, 'q' to quit.", 200,
             JPainter::kHAlignLeft, p.GetLineHeight());

    // Call the generic drawing routing (same for printing)
    DrawStuff(p);
}

/******************************************************************************
 DrawStuff (private)

 ******************************************************************************/

void
PrintWidget::DrawStuff
    (
    JPainter& p
    )
{
    // Set pen color
    p.SetPenColor((GetColormap())->GetBlackColor());

    // Find out how many points there are
    // There are count/2 lines
    JSize count = itsPoints->GetElementCount();

    // Loop through the points by twos
    for (JSize i = 1; i <= count; i += 2)
        {
        // Draw the line
        p.Line(itsPoints->GetElement(i), itsPoints->GetElement(i+1));
        }
}

/******************************************************************************
 HandleMouseDown (virtual protected)

    This gets called by the event loop every time a mouse button is pressed.

    pt is where the mouse was clicked, in Bounds coordinates.

    button is the index of the mouse button being pressed.

    clickCount is the number of times that this button has been pressed
    in rapid succession.

    buttonStates tells the state of all the mouse buttons.
    Refer to JXButtonStates.h for more information.

    modifiers contains information about modifier keys like Shift and
    Control.  Refer to JXKeyModifiers.h for more information.

 ******************************************************************************/

void
PrintWidget::HandleMouseDown
    (
    const JPoint&            pt,
    const JXMouseButton      button,
    const JSize              clickCount,
    const JXButtonStates&    buttonStates,
    const JXKeyModifiers&    modifiers
    )
{
    // Check to see if the left button was pressed
    if (button == kJXLeftButton)
        {
        // Create the drag painter to draw the rubber-band like lines
        JPainter* p = CreateDragInsidePainter();

        // Start the first line
        p->Line(pt, pt);
        }

    // Initialize the current points
    itsStartPt = itsPrevPt = pt;
}

/******************************************************************************
 HandleMouseDrag (virtual protected)

    This gets called as often as possible by the event loop as long as
    a mouse button is pressed.

    pt is where the mouse is, in Bounds coordinates.

    buttonStates tells the state of all the mouse buttons.
    Refer to JXButtonStates.h for more information.

    modifiers contains information about modifier keys like Shift and
    Control.  Refer to JXKeyModifiers.h for more information.

 ******************************************************************************/

void
PrintWidget::HandleMouseDrag
    (
    const JPoint&            pt,
    const JXButtonStates&    buttonStates,
    const JXKeyModifiers&    modifiers
    )
{
    // Check to see if the window was scrolled
    const JBoolean scrolled = ScrollForDrag(pt);

    // Get the drag painter that we created in mouse down
    JPainter* p = GetDragPainter();

    // Make sure that the left button is pressed,
    // that we have moved,
    // and that a drag painter exists
    if (buttonStates.left() && pt != itsPrevPt && p != NULL)    // p is NULL for multiple click
        {

        // Draw line depending on whether or not we scrolled
        if (!scrolled)
            {
            p->Line(itsStartPt, itsPrevPt);
            }
        p->Line(itsStartPt, pt);
        }

    // Remember the current point
    itsPrevPt = pt;
}

/******************************************************************************
 HandleMouseUp (virtual protected)

    This gets called by the event loop every time a mouse button is released.

    pt is where the mouse was released, in Bounds coordinates.

    button is the index of the mouse button being pressed.

    buttonStates tells the state of all the mouse buttons.
    Refer to JXButtonStates.h for more information.

    modifiers contains information about modifier keys like Shift and
    Control.  Refer to JXKeyModifiers.h for more information.

 ******************************************************************************/

void
PrintWidget::HandleMouseUp
    (
    const JPoint&            pt,
    const JXMouseButton      button,
    const JXButtonStates&    buttonStates,
    const JXKeyModifiers&    modifiers
    )
{
    // Get the drag painter that we created in mouse down
    JPainter* p = GetDragPainter();

    // Make sure that the left button is pressed,
    // and that a drag painter exists
    if (button == kJXLeftButton && p != NULL)    // p is NULL for multiple click
        {
        // Erase the last line that was drawn
        p->Line(itsStartPt, itsPrevPt);

        // Delete the drag painter
        DeleteDragPainter();

        // Add this set of points to our JArray
        itsPoints->AppendElement(itsStartPt);
        itsPoints->AppendElement(itsPrevPt);

        // Tell the widget to redraw itself
        Refresh();
        }
}

/******************************************************************************
 HandleKeyPress (virtual)

    This gets called by the event loop every time a key is pressed.

    If the key that was pressed had an ASCII equivalent, then 'key'
    contains the ASCII value.  Otherwise, 'key' contains the X KeySym
    value, as defined in X11/keysym.h.

    modifiers contains information about modifier keys like Shift and
    Control.  Refer to JXKeyModifiers.h for more information.

 ******************************************************************************/

void
PrintWidget::HandleKeyPress
    (
    const int key,
    const JXKeyModifiers& modifiers
    )
{
    // Check if the 'c' key was pressed
    // If so, we want to clear the window
    if (key == 'c')
        {
        // remove all of the points from the JArray
        itsPoints->RemoveAll();

        // Redraw
        Refresh();
        }
 
    // Check if the 'q' key was pressed
    else if (key == 'q')
        {
        // Quit the application if 'q' was pressed
        (JXGetApplication())->Quit();
        }
 
    // If anything else was pressed, pass it up the inheritance tree
    else
        {
        JXScrollableWidget::HandleKeyPress(key,modifiers);
        }
}

PrintWidget header file:

/******************************************************************************
 PrintWidget.h

    Interface for the PrintWidget class

    Written by Glenn Bach - 1997.

 ******************************************************************************/

#ifndef _H_PrintWidget
#define _H_PrintWidget

#include <JXScrollableWidget.h>
#include <JArray.h>

class JPrinter;
class JPainter;

class PrintWidget : public JXScrollableWidget
{
public:

    PrintWidget(JXScrollbarSet* scrollbarSet, JXContainer* enclosure,
             const HSizingOption hSizing, const VSizingOption vSizing,
             const JCoordinate x, const JCoordinate y,
             const JCoordinate w, const JCoordinate h);

    virtual ~PrintWidget();

    void    Print(JPrinter& p);

    virtual void    HandleKeyPress(const int key,
                                   const JXKeyModifiers& modifiers);

protected:

    virtual void    Draw(JXWindowPainter& p, const JRect& rect);
    virtual void    HandleMouseDown(const JPoint& pt, const JXMouseButton button,
                                    const JSize clickCount,
                                    const JXButtonStates& buttonStates,
                                    const JXKeyModifiers& modifiers);
    virtual void    HandleMouseDrag(const JPoint& pt, const JXButtonStates& buttonStates,
                                    const JXKeyModifiers& modifiers);
    virtual void    HandleMouseUp(const JPoint& pt, const JXMouseButton button,
                                  const JXButtonStates& buttonStates,
                                  const JXKeyModifiers& modifiers);

private:

    // used during drag

    JPoint    itsStartPt;
    JPoint    itsPrevPt;

    JArray<JPoint>* itsPoints;

private:

    void    DrawStuff(JPainter& p);

    // not allowed

    PrintWidget(const PrintWidget& source);
    const PrintWidget& operator=(const PrintWidget& source);
};
 

#endif

The PrintWidgetDir object - PrintWidgetDir .cc and

PrintWidgetDir .h

The object that holds the window is a PrintWidgetDir object which is derived from JXWindowDirector.

PrintWidgetDir source file:

/******************************************************************************
 PrintWidgetDir.cc

    BASE CLASS = JXWindowDirector

    Written by Glenn Bach - 1997.

 ******************************************************************************/

#include "PrintWidgetDir.h"
#include "PrintWidget.h"
#include <JXWindow.h>
#include <JXScrollbarSet.h>
#include <JXPSPrinter.h>
#include <JXTextButton.h>
#include <JXDialogDirector.h>
#include <jAssert.h>

/******************************************************************************
 Constructor

 ******************************************************************************/

PrintWidgetDir::PrintWidgetDir
    (
    JXDirector* supervisor
    )
    :
    JXWindowDirector(supervisor)
{
    BuildWindow();

    // Create the printer object
    itsPrinter = new JXPSPrinter(GetDisplay(), (GetWindow())->GetColormap());
    assert( itsPrinter != NULL );

    // Initialize the print setup dialog box - its created as needed
    itsPrintSetupDialog = NULL;
}

/******************************************************************************
 Destructor

 ******************************************************************************/

PrintWidgetDir::~PrintWidgetDir()
{
    // We need to delete this, the window will delete everything else
    delete itsPrinter;
}

/******************************************************************************
 Receive (virtual protected)

 ******************************************************************************/

void
PrintWidgetDir::Receive
    (
    JBroadcaster*    sender,
    const Message&   message
    )
{
    // Check if the print button was pressed
    if (sender == itsPrintButton && message.Is(JXButton::kPushed))
        {
        // Start the printing process by opening the dialog
        itsPrintSetupDialog = itsPrinter->BeginUserPrintSetup(this);
 
        // We need to know when the dialog has closed
        ListenTo(itsPrintSetupDialog);
        }
 
    // This is the dialog's closing message
    else if (sender == itsPrintSetupDialog &&
             message.Is(JXDialogDirector::kDeactivated))
        {
        // See if the user cancelled the print job
        if (itsPrinter->EndUserPrintSetup(message))
            {
            // If the user didn't cancel, print
            itsWidget->Print(*itsPrinter);
            }
        // The dialog will be deleted automatically
        itsPrintSetupDialog = NULL;
        }

    else
        {
        // Pass the message up the inheritance tree
        JXWindowDirector::Receive(sender, message);
        }
}

/******************************************************************************
 BuildWindow
          This is a convenient and organized way of putting all of the initial
     elements into a window. This will keep the constructor less cluttered.

 ******************************************************************************/

void
PrintWidgetDir::BuildWindow()
{
    // Create the window
    JXWindow* window = new JXWindow(this, 300,200, "Printing Test Program");
    assert( window != NULL );

    // Give the window to the director
    SetWindow(window);

    // Set the window sizing
    window->SetMinSize(300,200);
    window->SetMaxSize(800,600);

    // Create the print button
    itsPrintButton =
        new JXTextButton("Print", window,
            JXWidget::kHElastic, JXWidget::kVElastic,
            0, 0, 300, 20);

    // We need to hear when the button has been pressed
    ListenTo(itsPrintButton);

    // Create the scrollbar set
    JXScrollbarSet* scrollbarSet =
        new JXScrollbarSet(window,
            JXWidget::kHElastic, JXWidget::kVElastic, 0,20, 300,180);
    assert( scrollbarSet != NULL );

    // Create the custom widget with the scrollbarset as its enclosure
    PrintWidget* widget =
        new PrintWidget(scrollbarSet, scrollbarSet->GetScrollEnclosure(),
            JXWidget::kHElastic, JXWidget::kVElastic,
            0, 0, 10, 10);
    assert( widget != NULL );

    // Fit the widget within the scrollbarset enclosure
    widget->FitToEnclosure(kTrue, kTrue);
    itsWidget = widget;
}

PrintWidgetDir header file:

/******************************************************************************
 PrintWidgetDir.h

    Interface for the PrintWidgetDir class

    Written by Glenn Bach - 1997.

 ******************************************************************************/

#ifndef _H_PrintWidgetDir
#define _H_PrintWidgetDir

#include <JXWindowDirector.h>

class JXPSPrinter;
class PrintWidget;
class JXTextButton;
class JXDialogDirector;

class PrintWidgetDir : public JXWindowDirector
{
public:

    PrintWidgetDir(JXDirector* supervisor);

    virtual ~PrintWidgetDir();

protected:

    virtual void    Receive(JBroadcaster* sender, const Message& message);

private:

    JXPSPrinter*         itsPrinter;
    JXDialogDirector*    itsPrintSetupDialog;
    PrintWidget*         itsWidget;
    JXTextButton*        itsPrintButton;

private:

    void BuildWindow();

    // not allowed

    PrintWidgetDir(const PrintWidgetDir& source);
    const PrintWidgetDir& operator=(const PrintWidgetDir& source);
};
 

#endif

The function main - printing.cc

/******************************************************************************
 printing.cc
 
 Written by Glenn Bach - 1997.

 ******************************************************************************/

#include "PrintWidgetDir.h"
#include <JXApplication.h>
#include <jAssert.h>

/******************************************************************************
 main

 ******************************************************************************/

int
main
    (
    int      argc,
    char*    argv[]
    )
{
    // Create the application
    JXApplication* app = new JXApplication(&argc, argv);
    assert( app != NULL );

    // Create the window director
    PrintWidgetDir* mainDir = new PrintWidgetDir(app);
    assert( mainDir != NULL );

    // Activate the window director
    mainDir->Activate();

    // Start the event loop
    app->Run();
    return 0;
}