Virtual Developer Workshop: Containerized Development with Docker
Rather than provide a stocking stuffer for one little boy or girl, Santa sent the response to me. (We have pretty good distribution at codeguru.com, and the audience is appropriate.)
Many of you may have firmly resolved this issue in your minds one way or the other. To make my case though, I have demonstrated a splitter capability without making the capability into a control. You may find that code useful, and there may be some perspectives relative to components that you haven't thought of yet. You are invited to read on.
Implementing a Quick Splitter Control in VB6
If you haven't seen one before, a splitter control is usually implemented as a vertical or horizontal bar representing a division in the screen real estate used by forms. By dragging the splitter control users can change the relative amount of form real estate based on the direction the splitter is moved. For example, drag a vertical splitter left and the amount of spaced allocated to the left of the splitter is decreased and the right side is increased. Drag the splitter right and the opposite effect occurs. More space left and less space right. Figure 1 shows the splitter as it appears implemented in this article.
Figure 1: The blue vertical section represents the splitter behavior implemented by the code listing.
The idea behind a splitter control is that users may have more interest in one section of a form than another at a particular moment in time, but that interest may vary over time. A practical example can be found in the Windows Explorer shown in figure 2.
Figure 2: A practical example of a splitter allows the user to resize the folders view or the files view depending on which area holds the greatest interest at a given moment.
When the user is interested in navigating then more room can be given to the folders view on the left. When the user is looking for particular file then more room can be given to the files view on the right. The splitter is represented by the thin, gray, vertical band between the two views.
Coding the Splitter BehaviorTo implement the splitter behavior in VB6 we will use three Frame controls. One Frame control will represent the left region, a second will represent the right region, and a third will represent the splitter itself. Using this strategy all of the controls for such a form will be placed on the left or right frame. The frame-splitter will be used to resize the left and right regions based on the movement of the splitter. Listing 1 contains the complete implementation of vertical-splitting behavior. (I refer to this as a behavior because we are not creating a splitter control here, only implementing the behavior.)
Listing 1: Implementing Splitting behavior in VB6.
1: ' Form1.frm - Demonstrates splitting behavior using forms. 2: ' Copyright (c) 2001. All Rights Reserved. 3: ' Paul Kimmel. Okemos, MI USA. email@example.com 4: 5: Option Explicit 6: Private Moving As Boolean 7: Private LeftControl As Control 8: Private RightControl As Control 9: 10: 11: Private Sub Form_Load() 12: Set LeftControl = Frame1 13: Set RightControl = Frame2 14: End Sub 15: 16: Private Sub Form_MouseMove(Button As Integer, _ 17: Shift As Integer, X As Single, Y As Single) 18: If (Moving And Button = 1) Then 19: Splitter.Left = X 20: Call ResizeSplitter 21: Call ResizeLeftControl 22: Call ResizeRightControl 23: End If 24: End Sub 25: 26: Private Sub Form_MouseUp(Button As Integer, _ 27: Shift As Integer, X As Single, Y As Single) 28: If (Moving) Then 29: Moving = False 30: Splitter.MousePointer = 0 31: End If 32: End Sub 33: 34: Private Sub ResizeSplitter() 35: Splitter.Top = 0 36: Splitter.Height = Form1.Height 37: End Sub 38: 39: Private Sub ResizeLeftControl() 40: LeftControl.Left = 0 41: LeftControl.Top = 0 42: LeftControl.Height = Form1.Height 43: LeftControl.Width = Splitter.Left 44: End Sub 45: 46: Private Sub ResizeRightControl() 47: RightControl.Left = Splitter.Left + Splitter.Width 48: RightControl.Top = 0 49: RightControl.Height = Form1.Height 50: RightControl.Width = Form1.Width - RightControl.Left 51: End Sub 52: 53: Private Sub Form_Resize() 54: Call ResizeSplitter 55: Call ResizeLeftControl 56: Call ResizeRightControl 57: End Sub 58: 59: Private Sub Frame1_MouseMove(Button As Integer, _ 60: Shift As Integer, X As Single, Y As Single) 61: Call Form_MouseMove(Button, Shift, X, Y) 62: End Sub 63: 64: Private Sub Frame1_MouseUp(Button As Integer, _ 65: Shift As Integer, X As Single, Y As Single) 66: Call Form_MouseUp(Button, Shift, X, Y) 67: End Sub 68: 69: Private Sub Frame2_MouseMove(Button As Integer, _ 70: Shift As Integer, X As Single, Y As Single) 71: Call Form_MouseMove(Button, Shift, Frame2.Left + X, Y) 72: End Sub 73: 74: Private Sub Frame2_MouseUp(Button As Integer, _ 75: Shift As Integer, X As Single, Y As Single) 76: Call Form_MouseUp(Button, Shift, X, Y) 77: End Sub 78: 79: Private Sub Splitter_DblClick() 80: Moving = True 81: Splitter.MousePointer = 9 82: End Sub 83: 84: Private Sub Splitter_MouseUp(Button As Integer, _ 85: Shift As Integer, X As Single, Y As Single) 86: Call Form_MouseUp(Button, Shift, X, Y) 87: End Sub
The code is relatively straightforward but surprisingly long. I won't explain each line because it is easy to follow and there are no particularly difficult methods. To summarize, the code treats one frame as a splitter and two other frames as the regions to be split. When the form is resized the splitter and the left and right region are resized to use all available space.
The code works by tracking mouse activity. Double-click on the splitter-frame and as long the left mouse button is down the splitter follows the mouse movement, resizing left and right regions accordingly. Release the mouse and the splitter stops tracking the mouse movement.
I want to take a moment to be clear about something. Listing 1 is not object-oriented code. Listing 1 is structured code written in an object-based framework. (In case you skipped the introduction, this is where I start making my case for classes and components.)
What's Wrong with Structured Programming?
Assuming you buy my argument that listing 1 is not object-oriented then you might ask, well then, what is wrong with code like the code in listing 1? The answer is nothing as long you know it is not object-oriented, and as long as you intended to write structured code. But, why would you ever want to write structured code?
Unfortunately, I have had the occasional misfortune of (briefly) working for managers that made statements like "we don't have time for modeling", "you write too many classes", and "we don't have time to create components". My rebuttal is that you only have time to model, write classes, and create components. What you do not have time to do is cut and paste.
Code like that in listing 1 can really only be reused if you save a second copy of the form or literally cut and paste the code into another form. (Both of these examples are cutting and pasting effectively.) In very simple examples cutting and pasting is a bit faster and cheaper, but that is where it ends. In applications, cutting and pasting is a "Death March" waiting to be born.
It must be remembered that most of software development costs occur after the initial code is written, over the life of a program. This means that every time you cut and paste, you will be paying an additional time to maintain the same code. Cut and paste the splitter behavior one time and you pay twice as much to own it. Cut and paste it three times, four times, or fives times, and, well, you can see that the splitter behavior becomes very expensive to own. Any developer, manager, or team that does not understand this concept is planning to fail, in a big way, too.
If you still don't believe me then rewrite the splitter without the Frame control and see how much code you have. Then, rewrite the code again without Windows API calls. Yes, I mean write your own windowing framework. Your 85 lines of code just escalated to upwards of 10,000,000 lines of code (if you're lucky).
To even suggest that object-oriented programming doesn't matter or components aren't important is naove. Ask yourself where transportation would be without oil refineries, spark plugs, or the combustion engine. Conceptualizing things into tidy little packages is something humans learn to do at a very early age and we're pretty good at it too. Convert the ability to abstract in a digital world and an architect is born.
What is the difference then between a class and a component? There is the real question.
Classes versus Components
To say that object-oriented languages haven't lived up to their promise is very short sighted. That assumes that OO is at the end of our collective evolutionary understanding. OO is just a way-station along the journey.
A big part of what is OO is the class. (Classes and objects are not the same thing. This is imperative to understanding OO, so I though I'd interject it on principle.) A class is a blueprint of a noun, generally. More precisely a class is an aggregate data type comprised of one or many of the following: fields, events, properties, and methods. Generally, classes describe something, and occasionally classes act as a convenient place to organize methods only or data only. (Often data-only or method-only classes are not very good classes, but that's another article.)
Within the last ten years more programmers were introduced to the concept of the class. (This happened with the invention of C++, although C++ was not the first OO programming language by far.)
The next step in the evolution of OO was the component. What is the difference between a class and component? Technically nothing. There is no difference between a class and a component. Philosophically, the difference between a class and a component is that components represent a class that may be very complex that solves a problem all by itself.
When implementing a splitter we would be writing a class, but we would call that implementation a component. The reason for this is that the splitter solves a whole problem, albeit a small one, all by itself. Another pair of examples is demonstrated by the DateTime class—like the one in VB.NET—and a calendar. Both DateTime and Calendar are technically implemented as classes. The calendar, however, solves a more complete solution and gets the dubious distinction of being a component.
For our industry to progress and for developers to be able to build continually more complex solutions, we must continue to find better ways to manage complex problems in tidy little packages. Without classes our ability as software engineers to solve problems is severely handicapped. OO doesn't guarantee that we can program better than non-OO programmers. OO does mean that we have better ways of organizing very complex ideas. This means the potential for greater problem solving exists with OO. This also means that greater problem-solving potential exists if we use components.
I don't know what the next evolutionary step in software development languages will be, but I do know that ignoring OO is akin to solving problems with a mind that has stopped evolving somewhere between 1890 and 1970. A lot has changed since 1970.
Object-oriented design and programming is not the end of our journey. Greater ways of communicating with programming languages will be invented. OO is an improvement over structure programming. This is clear by the evolution of very complex and engaging software.
Software development is still in its infancy. OO doesn't guarantee success, but does represent a significantly greater opportunity for success than do non-object-oriented practices. It is clear that modest improvements have been made in the last ten years by emphasizing the component as a more complete class, but we have a long way to go. Those denying OO are like cave dwellers denying fire, electricity, the television, or the Internet.
Ugh! Come into the light.
About the Author
Paul Kimmel is a freelance writer for Developer.com and CodeGuru.com. Look for cool Visual Basic .Net topics in his upcoming book Visual Basic .Net Unleashed. Paul founded Software Conceptions, Inc. in 1990. Contact Paul Kimmel at firstname.lastname@example.org for help building VB.NET applications or migrating VB6 applications to .NET.