Non-client mouse operations.
Previously, you saw how to modify the relationship between
the client and non client areas of a control so that you could make the
distinction between painting the parts of the window such as borders or system
buttons that have little relationship to the content of the control or window
and the content itself. You will remember that the advantage of modifying
the client size was that there was no need to compensate for window adornments
when you have to draw the window content. There is also a distinction
between the client and non client areas of the window when it comes to user
interaction as well. Consider the kind of window used to display a form
with a standard title bar and system buttons. This represents a
particular class of window that has a specific set of behaviors and which
implies a certain standard of operation when the user sees it on screen.
For example, the user knows that the title bar, contains the name of the program
or document currently being edited and that the buttons behave in a certain way.
In your own applications, The you may wish to create a
similar style of window that has a predictable behavior which is isolated from
the behavior of the client area so that you can reuse this "client wrapper" in
many different places. In order to do this you need to be able to receive
mouse input from the area so that you can differentiate between the user's
interaction with the objects in the client area and their desire to do something
with the executive, non-client, portion.
Once again, in order to do this, we have to resort to a lower
level of interaction than is provided by the standard Windows Forms controls or
forms And use the WndProc method to process low-level non-client windows
messages as they arrive.
The demonstration for this article is a simple one
which puts a track-bar style control in the title bar that controls the overall
opacity of the form.
Messages.
WM_NCPAINT is used to create the graphic for a slider which
is embedded in the title bar as shown in figure 1.

Figure 1. The opacity slider.
The draw process chooses a rectangle into which the slider
should fit without interfering with the other buttons in the title bar. A scale
is drawn and a button placed according to the value of the transparency which is
initially zero.
WM_NCLBUTTONDOWN is caught and a test made to see if the
pointer is in the button. If it is, a semaphore is set which signifies the
button has been grabbed. The button will be redrawn in a pressed state. Note
that all non-client mouse values are in screen, not client positions but the
usual PointToClient method will cause us problems because the client is offset
within the window. To obtain an accurate position within the non-client area we
just need to subtract the location of the form. For controls within a form
you'll need to find the control's ultimate parent and compound all the offsets
to find the correct values. This message is also used to store the pixel offset
of the pointer from the left side of the button. This enables the button to be
moved in synchronization with the pointer.
WM_NCMOUSEMOVE enables you to move the slider. The value is
calculated according to the current size of the scale which changes with the
window size. The value is applied to the window and the scale is redrawn again
using the SendMessage API to send another WM_NCPAINT to the form.
WM_NCLBUTTONUP releases the button and flags the end of the
operation.
Non-client operations don't always follow strict rules. For
example, if the window is restored after being minimized the non-client area is
repainted without using the WM_NCPAINT message. The demo overrides the
OnSizeChanged to ensure that the slider is repainted.
The code for this example is shown in
this listing.
You can find the Source Code files here.
This concludes this short series on Non-Client operations.
Return to Part 1.
Return to the main menu.