2000-08-14 05:44:35 -04:00
|
|
|
\chapter{Drawing on device contexts}\label{chapdrawing}
|
|
|
|
\pagenumbering{arabic}%
|
|
|
|
\setheader{{\it CHAPTER \thechapter: DRAWING ON DEVICE CONTEXTS}}{}{}{}{}{{\it CHAPTER \thechapter: DRAWING ON DEVICE CONTEXTS}}%
|
|
|
|
\setfooter{\thepage}{}{}{}{}{\thepage}%
|
|
|
|
|
2000-12-22 10:56:48 -05:00
|
|
|
\section{The concept of device contexts}
|
|
|
|
|
|
|
|
Device contexts, commonly referred as DCs, represent more or less anything
|
|
|
|
you can draw into, i.e. a window, a bitmap, the screen, a printer, a Postscript
|
|
|
|
file, most recently even an SVG file. There is one abstract base class (wxDC)
|
|
|
|
which defines the interface for all other classes so that drawing code for
|
|
|
|
one device context can be used for all others as well - with certain limitation
|
|
|
|
as the hardware specifies (e.g. you cannot read a pixel from a printer).
|
|
|
|
|
|
|
|
\section{Drawing into windows}
|
|
|
|
|
|
|
|
Let's start with the most simple case: you want to draw a line in a window.
|
|
|
|
Or rather not the window, but its client area, the usually white or grey
|
|
|
|
large area that is surrounded by the window's decorations such as its border
|
|
|
|
which you normally would not want to draw over.
|
|
|
|
|
|
|
|
In addition to defining classes that represent devices, wxWindows has a few
|
|
|
|
of classes that define colours and so-called pens and brushes. A pen is used
|
|
|
|
for drawing lines (which can be a curve or a rectangle) whereas brushes are
|
|
|
|
used to paint areas, such as a filled rectangle or a filled circle. Indeed,
|
|
|
|
you can use both at the same time for drawing a rectangle which is both filled
|
|
|
|
and has a border. If you want to draw a red rectangle with a black border,
|
|
|
|
you will do this:
|
|
|
|
|
|
|
|
\begin{verbatim}
|
|
|
|
void MyWindow::DrawSomething()
|
|
|
|
{
|
|
|
|
wxClientDC dc(this);
|
|
|
|
|
|
|
|
dc.SetPen( *wxBLACK_PEN );
|
|
|
|
dc.SetBrush( *wxRED_BRUSH );
|
|
|
|
|
|
|
|
dc.DrawRectangle( 0, 0, 100, 100 );
|
|
|
|
}
|
|
|
|
\end{verbatim}
|
|
|
|
|
|
|
|
If you want to draw a rectangle without any border, you can use the special
|
|
|
|
oen wxTRANSPARENT_PEN, if the rectangle is not supposed to be filled with
|
|
|
|
any colour, you use the special brush wxTRANSPARENT_BRUSH. When using both
|
|
|
|
these special classes, you could draw an invisible rectangle like this:
|
|
|
|
|
|
|
|
\begin{verbatim}
|
|
|
|
void MyWindow::DrawNothing()
|
|
|
|
{
|
|
|
|
wxClientDC dc(this);
|
|
|
|
|
|
|
|
dc.SetPen( *wxTRANSPARENT_PEN );
|
|
|
|
dc.SetBrush( *wxTRANSPARENT_BRUSH );
|
|
|
|
|
|
|
|
dc.DrawRectangle( 0, 0, 100, 100 );
|
|
|
|
}
|
|
|
|
\end{verbatim}
|
|
|
|
|
|
|
|
Now what happens when you window gets obscured by another window and
|
|
|
|
then returns to the surface again? The rectangle will not appear again
|
|
|
|
because a window does not remember what has been drawn into it. Instead,
|
|
|
|
your program has to remember what to draw and where and it will receive
|
|
|
|
a so called wxPaintEvent indicating that some region has been unobscured
|
|
|
|
and needs repainting. In order to catch such an event so that you can
|
|
|
|
react appropriately to it, you will have to set up an event handler
|
|
|
|
like this:
|
|
|
|
|
|
|
|
\begin{verbatim}
|
|
|
|
BEGIN_EVENT_TABLE(MyWindow, wxWindow)
|
|
|
|
EVT_PAINT (MyWindow::OnPaint)
|
|
|
|
END_EVENT_TABLE()
|
|
|
|
|
|
|
|
void MyWindow::OnPaint( wxPaintEvent &event )
|
|
|
|
{
|
|
|
|
wxPaintDC dc(this);
|
|
|
|
|
|
|
|
dc.SetPen( *wxBLACK_PEN );
|
|
|
|
dc.SetBrush( *wxRED_BRUSH );
|
|
|
|
|
|
|
|
dc.DrawRectangle( 0, 0, 100, 100 );
|
|
|
|
}
|
|
|
|
\end{verbatim}
|
|
|
|
|
|
|
|
Note that this time, you have to use a wxPaintDC as these are used
|
|
|
|
in connection with wxPaintEvents. Note also, that every such handler
|
|
|
|
has to use a wxPaintDC even of you (for the moment) don't draw anything.
|
|
|
|
If there is no such wxPaintDC, your program will not work under Windows.
|
|
|
|
|
|
|
|
One difference between a wxPaintDC and a wxClientDC is that the wxPaintDC
|
|
|
|
always sets a clipping region to the region of the window that was
|
|
|
|
unobscured with the effect that all drawing commands will be clipped to
|
|
|
|
that region. This leads to a reduction of flicker as only those
|
|
|
|
areas of the window get redrawn, which actually need to get redrawn.
|
|
|
|
|
|
|
|
\section{Querying the update region}
|
|
|
|
|
|
|
|
Call me lazy:
|
|
|
|
|
|
|
|
\begin{verbatim}
|
|
|
|
BEGIN_EVENT_TABLE(MyWindow, wxWindow)
|
|
|
|
EVT_PAINT (MyWindow::OnPaint)
|
|
|
|
END_EVENT_TABLE()
|
|
|
|
|
|
|
|
void MyWindow::OnPaint( wxPaintEvent &event )
|
|
|
|
{
|
|
|
|
wxPaintDC dc(this);
|
|
|
|
|
|
|
|
if (IsExposed( 0, 0, 100, 100))
|
|
|
|
{
|
|
|
|
dc.SetPen( *wxBLACK_PEN );
|
|
|
|
dc.SetBrush( *wxRED_BRUSH );
|
|
|
|
|
|
|
|
dc.DrawRectangle( 0, 0, 100, 100 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
\end{verbatim}
|
|
|
|
|
2000-08-14 05:44:35 -04:00
|
|
|
|