Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages

## Creating a painter

### Implementing an own painter

One of the most important aspects of the background_wnd is the separation of the actual drawing from the window-logic. background_wnd takes care of managing a memory-dc, Z-Order, drawing-rect, transparency, visibility of painters and so on. You only have to concentrate on creating a painter. This is very easy:

- Derive a class from painter_base. Here's an overview of painter_base:

      namespace win32 { namespace gui {

           // painter_base: abstract base class of all painters
           struct painter_base
           {
                // c'tor and virtual destructor
                painter_base();
                virtual ~painter_base();

                // virtual functions
                virtual painter_base* clone() const = 0;
                virtual void draw(HDC hDC, int cx, int cy) = 0;
                virtual bool is_opaque(int cx, int cy) const;

           protected:
                // only copy with clone()
                painter_base(const painter_base&);
                const painter_base& operator= (const painter_base&);
           };

      } }  // namespace win32::gui

- Implement the pure virtual function `draw()`. The arguments are:

      hDC     - The dc on which the painting operations should occur
      cx, cy  - The width and height of the area where the painting shall occur (see drawing-rect)

  You don't have to care about clipping or transparency: background_wnd does it for you!
- Implement the pure virtual function `clone()`. You are forced to return an object which is allocated with `new`. If you don't return such an object your application is likely to crash. Normally you will implement this function like this:

      your_painter* your_painter::clone() const
      {
           return new your_painter(*this);
      }

- If the constructor takes one or two parameters add typedefs for the parameter types. They must be typedefed to `param0` and `param1`
- To improve performance of background_wnd it is advisable to override `is_opaque()`. If you know your painter draws the whole area opaque you can return true in this function. background_wnd will check this and if a painter is completely underneath your painter (lower in Z-Order and drawing-rect is completely overlapped by the drawing-rect of your painter) background_wnd will not call `draw()` of the overlapped painter. Of course background_wnd takes care of the transparency that could be applied to your painter ;-). By default this function returns false. The arguments are the same which are passed to `draw()` except for hDC
- When your painter throws exceptions you should use the background_wnd-exceptions (see here)

To understand the basic concept and the implementation details I recommend that you study layout_painter or stretch_painter because these two classes show you some nice techniques that are possible with the painter-concept ;-)

### Aggregating painters

Of course you can aggregate and use other painters in your `draw()`-function. stretch_painter does exactly that:

    void stretch_painter::draw(HDC hDC, int cx, int cy)
    {
         ...
         transparent_painter p(cr_not_used_);
         p.set_painter<stretch_painter_helper> (hPainterDC, wnd_size(cx, cy));
         p.draw(hDC, rc_stretch_.width(), rc_stretch_.height());
         ...
    }

But that is not all: I included a class which holds another painter - painter_holder. You can derive your painter from painter_holder if you want to manipulate the appearance of a painter. Good examples are transparent_painter and stretch_painter: the former draws another painter but with one color transparent while the latter draws the painter stretched.
Here's the definition of painter_holder:

    namespace win32 { namespace gui {

         // painter_holder
         struct painter_holder
         {
              // exceptions
              typedef bg_wnd::general_exception<painter_holder, 0> no_painter;
              typedef bg_wnd::general_exception<painter_holder, 1> invalid_painter_cast;

              // the big 4
              painter_holder(painter_base* pPainter = NULL);
              painter_holder(const painter_holder& holder);
              virtual ~painter_holder();
              const painter_holder& operator= (const painter_holder& holder);

              // set the painter and release it
              void release_painter();
              void set_painter(const painter_base& painter);
              template<class Painter> void set_painter();
              template<class Painter> void set_painter(typename Painter::param0 param);
              template<class Painter> void set_painter(typename Painter::param0 param0, typename Painter::param1 param1);

              // painter access
              painter_base& get_painter() const;
              template<class Painter> Painter& get_painter() const;
              bool painter_available() const;

              void swap(painter_holder& holder);
         };

    } }  // namespace win32::gui

Note:
  - The non-template version of `set_painter()` creates a copy of the passed painter by invoking clone()
  - When you call `get_painter()` and there is no painter a `painter_holder::no_painter`-exception is thrown. If you call the templated function and the painter can't be casted to Painter (dynamic type of the painter is not Painter) a `painter_holder::invalid_painter_cast`-exception is thrown.

| by Steven Weiss. You can contact me at steven11@gmx.de.