| home
Part I Introduction Ernest Murphy ernie@surfree.com October 18, 2000 Get the source code
here.
Abstract:
Splitter bars are a distinctive visual control element that help organize a large amount of information in a window. They allow your user to resize the relation between two panes of information. A very common example of a splitter is in Windows File Explorer, which uses a splitter bar to divide two panes of information. A vertical splitter bar application
is described here. In the sample code, a horizontal splitter bar application
is also included to cover both types of splitters.
Introduction:
Splitter bars are one of the least apparent window elements. They appear as a 4-pixel wide strip of nothing between two child windows. They provide user feedback to their being there by changing the mouse pointer to a horizontal resize pointer while over this bar. A search of MSDN will show splitters done in MFC and other libs. This is a shame, as a splitter is actually one of the simplest child window controls you can write.
At MOUSEDOWN, we save the X-Y point on the splitter where the mouse clicked, and invoke SetCapture to keep the mouse messages in our window. MOUSEUP is even simpler, just invoking ReleaseCapture and letting the mouse run free. MOUSEMOVE is where all the magic happens. Two things are first checked: That the left mouse button is down, and that it has moved relative to the initial click hit in MOUSEDOWN. If it has, the scroll window is moved the same distance, and the side windows are re-calculated. Note for a vertical splitter, only the X dimension is checked for the move, and for a horizontal splitter only the Y dimension.
One point in the client area that never moves and is always there for reference is the top left corner, or (0,0). We pass this point to ClientToScreen and we get the Screen dimensions of this point. Now we can subtract these screen dimensions from the dimensions we get back from GetWindowRect to convert from screen to client dimensions. In this way, we can compute a windows dimensions in client and width/height terms like so:
I will leave the details of how the child windows are calculated to anyone interested in wading through the source code. One last check we make is to see if either of the side windows is getting too small, and adjust the movement to the minimum window width. One last further note: When we run through the MOUSEMOVE code, we do a check if the movement is zero. This may seem odd, as how can the mouse move zero and still generate a MOUSEMOVE message? In truth, there are two ways a MOUSEMOVE message is generated. One is obvious, move the mouse over the window. The other is more subtle: move the window under the mouse. By checking for zero movements we get to skip the last loop of the MOUSEMOVE message, and insure we don't create an infinite loop checking the window we just moved a zero amount doesn't try to move zero again. Conclusion
One further note: The source code for this artical is basically the same as I orgionally developed for the first splitter class, though it has since been tweeked and changed to match the work done re-writing it into the dll form. Most of the re-write was done thruogh cut-and-paste. For example, the same winproc is shared between both programs. This is a useful approach to creating
a custom control library function, as most of the development work may
be done on a single executable, tested after a single compile and link
step. If I had started right off with a dll and a second test program,
it would have opened the question of "where is the bug? In the .exe or
the .dll?" This way, most bugs were already dead when the dll was newborn.
|