Step 4: Drawing in the window
You can find the source for Step 4 in the file STEP04.CPP in the
directory EXAMPLES\OWL\TUTORIAL. In this step, you'll add the ability to draw a line in
the window by pressing the left mouse button and dragging. To do this, you'll add a two
new events, WM_MOUSEMOVE and WM_LBUTTONUP, to the TDrawWindow response table, along with
functions to handle those events. You'll also add a TClientDC * to the class.
Adding new events
To let the user draw on the window, the application must handle a
number of events:
You need to add two macros
to the window class' response table, EV_WM_MOUSEMOVE and EV_WM_LBUTTONUP. The new response
table should look something like this:
DEFINE_RESPONSE_TABLE1(TDrawWindow, TWindow)
EV_WM_LBUTTONDOWN,
EV_WM_RBUTTONDOWN,
EV_WM_MOUSEMOVE,
EV_WM_LBUTTONUP,
END_RESPONSE_TABLE;
You also need to add the EvLButtonUp and
EvMouseMove functions to the TDrawWindow class.
Adding a TClientDC pointer
The scheme used in Step 3 to draw a line isn't very robust:
You can take care of both
of these problems rather easily by adding a new protected data member to
TDrawWindow. This data member is a TDC * called DragDC. It works this way:
| When the left mouse button is
pressed, the EvLButtonDown function is called. This function creates a new TClientDC and
assigns it to DragDC. It then sets the current point in DragDC to the point at which the
mouse was clicked. The code for this function should look something like this:
void
TDrawWindow::EvLButtonDown(uint, TPoint& point)
{
Invalidate();
if (!DragDC) {
SetCapture();
DragDC = new TClientDC(*this);
DragDC->MoveTo(point);
}
}
|
| When the left mouse button is
released, the EvLButtonUp function is called. If DragDC is valid (that is, if it
represents a valid device context), EvLButtonUp deletes it, setting it to 0. The code for
this function should look something like this:
void
TDrawWindow::EvLButtonUp(uint, TPoint&)
{
if (DragDC) {
ReleaseCapture();
delete DragDC;
DragDC = 0;
}
}
|
| When the mouse is moved, the
EvMouseMove function is called. This function checks whether the left mouse button is
pressed by checking DragDC. If DragDC is 0, either the mouse button has not been pressed
at all or it has been pressed and released. Either way, the user is not drawing, and the
function returns. If DragDC is valid, meaning that the left mouse button is currently
pressed down, the function draws a line from the current point to the new point using the
TWindow::LineTo function.
void
TDrawWindow::EvMouseMove(uint, TPoint& point)
{
if (DragDC)
DragDC->LineTo(point);
}
|
Initializing DragDC
You must make sure that DragDC is set to 0 when you construct the
TDrawWindow object:
TDrawWindow::TDrawWindow(TWindow *parent)
{
Init(parent, 0, 0);
DragDC = 0;
}
Cleaning up after DragDC
Because DragDC is a pointer to a TClientDC object, and not an
actual TClientDC object, it isn't automatically destroyed when the TDrawWindow object is
destroyed. You need to add a destructor to TDrawWindow to properly clean up. The only
thing required is to call delete on DragDC. TDrawWindow should now look something
like this:
class TDrawWindow : public TWindow
{
public:
TDrawWindow(TWindow *parent = 0);
~TDrawWindow() {delete DragDC;}
protected:
TDC *DragDC;
// Override member function of TWindow
bool CanClose();
// Message response functions
void EvLButtonDown(uint, TPoint&);
void EvRButtonDown(uint, TPoint&);
void EvMouseMove(uint, TPoint&);
void EvLButtonUp(uint, TPoint&);
DECLARE_RESPONSE_TABLE(TDrawWindow);
};
Note that, because the tutorial
application has now become somewhat useful, the name of the main window has been changed
from "Sample ObjectWindows Program" to "Drawing Pad":
SetMainWindow(new TFrameWindow(0, "Drawing Pad", new TDrawWindow));
Where to find more information
Here's a guide to where you can find more information on the topics
introduced in this step:
|