Hosted by
|
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:
- To start drawing the line, you have
to look for the user to press the left mouse button. This is already taken care of by
handling the WM_LBUTTONDOWN event.
- Once the user has pressed the left
button down, you have to look for them to move the mouse. At this point, you're drawing
the line. To know when the user is moving the mouse, catch the WM_MOUSEMOVE event.
- You then need to know when the user
is finished drawing the line. The user is finished when the left mouse button is released.
You can monitor for this by catching the WM_LBUTTONUP event.
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:
- In Step 3, you created a TClientDC
object in the EvLButtonDown function that was automatically destroyed when the function
returned. But now you need a valid device context across three different functions,
EvLButtonDown, EvMouseMove, and EvLButtonUp.
- You can catch the WM_MOUSEMOVE
event and draw from the current point to the point passed into the EvMouseMove handling
function. But WM_MOUSEMOVE events are sent out whenever the mouse is moved. You only want
to draw a line when the mouse is moved with the left button pressed down.
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:
- Event handling is discussed in
"Event handling" in the ObjectWindows Programmer's Guide.
- Device contexts and the TDC classes
are discussed in "Graphics objects" in the ObjectWindows Programmer's Guide.
- Predefined response table macros
and their corresponding event-handling functions are listed in Chapter 3 in the
ObjectWindows Reference Guide.
Prev
Up
Next
|