| home
Splitter
Bar:
Ernest Murphy ernie@surfree.com October 22, 2000 Get the control source
code and test application code.
Abstract:
A ready-for-prime-time Splitter Bar
control is demonstrated. This project builds on the three previous projects,
and is only explained in brief.
------------------------------------------------------------------------------------------ So far, we have only looked at vertical
splitter bars, but they may also be vertical.
Besides the obvious new horizontal splitter bar, there is something else significant this incarnation of the control performs: it can revise multiple adjacent controls. The horizontal bar has 3 controls (IDC_EDIT1, IDC_EDIT2, and IDC_SPLITTER2) in it's bottom pane. That means we must pass a LIST of window handles to our control. The easiest way to handle a list of arbitrary size is make the data itself indicate the list end; let's take our clue from character strings and define a NULL handle in the list as the list end. Let us describe the application code first, then show how this is handled by the control. To make the lists of these controls,
we use structures. Structures have the nice property of assigning default
values, so we can start all elements as zero. This also means we don't
have to use code to set the end of list NULL. For these two splitters,
these structures are formed:
A horizontal splitter needs a list of controls above and below it, a vertical splitter needs a list of left and right sides. These structs define the lists for all the window handles the two splitters will need. We can initialize these structures
like so:
That is all the code we need. For
resources, that too is simple:
Here, note the Splitter class has
morphed into two different controls, a horizontal (HSplitterCtrl) and vertical
(VSplitterCtrl) class. This is solely to give each a different default
cursor bitmap, as these bitmaps are strictly a class property, and may
not be changed for a particular class. If it could be set for a specific
instance, one set of could (with some extra internal conditionals) would
have sufficed.
The Control Library
The horizontal splitter class is a
simple change to the existing class. They are defined as such:
Both splitter classes get a data structure
to hold instance information. They are really the same structure, just
with some name changes to convey a bit more sense:
The lists of window handles as passed in by reference, i.e., the address of the list is pushed. This means the same code (with minor name changes) is used to store them, and will not be discussed. The handle data is handled with a
simple .WHILE loop. A local variable is set to the list pointer. This address
is loaded to eax. Windows are processed .WHILE eax != 0 (i.e., while the
current handle is not NULL). A NULL terminates the loop, and sends us on
to our next task. If we do loop, the LOCAL pointer is incremented by SIZEOF
DWORD (4) to point to the next handle to process. This loop is illustrated
in the following fragment:
One more trick was added into this
implementation. If you note in Windows Explorer, if you select the splitter
with a left click, you are unable to drag the mouse cursor outside of the
parent. This was included with a ClipRect inside the LBUTTONDOWN handler:
This clipping is canceled with a simple "invoke ClipCursor, NULL" inside LBUTTONUP. As I was making my first release of this (yesterday as I type), I noticed a minor bug: if a window was resized beyond it's minimum, and the mouse button released, it would pop to some uncertain size. I realized the re-size routine was getting confused, as it had partially moved/resized some windows before it determined this move was too much, so it would start over with a new smaller move. This was a problem because the starting
point was lost. The fix was to repeat this section of code twice, the first
time just to check if the min size was violated, and the second size to
do the actual move. Things are just fine now, thank you.
Conclusion:
|