|
STL represents a powerful set of standard routines. I've switched from using the comparibly wimpy container classes included in Power++ to those in the STL, and the STL containers are far more robust.
The best and most up-to-date implementation of the STL I've found is the SGI implementation. An adapted version is available from the Standard Template Library Adaptation Page at:
Download their STL distribution (or just click here). Also download this file (see below for how to use it). There are a number of other links to STL information there, too. Be sure to download the SGI STL documentation; it is in HTML format, which makes it easy to have it onscreen when you need it.
There are a couple of tweaks that need to be made to this distribution to get it to work well with Power++. They are:
Update! Doni Grande writes in to let us know that: "There is new release of the adapted SGI STL available, V2.031, which fixes several minor problems. This version works fine with Power++ without the modified version of stlcomp.hpp (available above). Just include the STL.HPP from above, and you should be able to use the STL. Unfortunately, the stl_debug mode still doesn't work, though.
I have found a second reason to avoid the WApplication class. If you try to "#include <stl.hpp>" so that it appears in WApplication.hpp, you will get errors because the new statement get redefined. The error is in main.cpp, but the application header is included by main. In order to use the STL, I have had to avoid including STL.hpp before the main function. Despite this significant restriction of how the STL can be used in Power++, I have been using the STL... it is one of the most significant developments in C++ in the last several years and needs to be well integrated into all C++ implementations.
Update! Andres Galeano with information on redefining the new and delete operators. Quoting straight from the Manual:
In order to provide debugging support for new and delete, the Power++ component library defines new and delete as macros. This may cause problems if you try to use any Powersoft/Watcom C++ container classes that override the new operator.
In order to get around such problems, you must undefine the Power++ new and delete before including a C++ container class, then redefine them afterward. The following code shows an example:
#undef new #include <confile.hpp>
#undef delete
#include "wnew.hpp"
In this example, confile.hpp contains the container class definitions you want to use in your program. The statement #include "wnew.hpp" obtains the necessary instructions to redefine the Power++ new and delete operators.
Including wnew.hpp works specifically because the Watcom C++ container classes define their versions of new and delete with inline code. This means that the inline definitions of new and delete apply within the container class, but the Power++ definitions can still be re-established by wnew.hpp. If your code changes the definitions of new and delete in some other way, it may not be sufficient just to include wnew.hpp. Specifically, you may have to define an operator with the prototype:
void *operator new( size_t , const WChar *, const WChar *, WULong );
to satisfy macros in wnew.hpp.
If you perform any special operations with new (such as placement operations), you should perform the same kind of undefine/redefine operation.
If memory cannot be allocated in a new operation, the default handler for new simply returns NULL. If you want a different behaviour, you must set your own new handler as discussed below. |
If you #define the symbol _NO_REDEFINE_NEW, the macros WREDEFINENEW and WREDEFINEDELETE (used in redefining new and delete) expand to nothing. This prevents the library from redefining new and delete. You may #define _NO_REDEFINE_NEW if you intend to write your own new handler and don't want it overridden by the library.
See the rest of the help topic The new and delete operators for information on setting your own handler for new.
Note that we have some more juicy STL information coming up for next week's tip, so stay tuned! If any of you have any STL/Power++ tips, please send them in so that we can all benefit!
Note that many of the Power++ components are wrappers of the Win32 common controls. Therefore Win32 functions and macros that apply to Win32 common controls usually also work with the Power++ components.
By default, controls that you place on a form, are private to that form (well, protected actually, but we don't need to worry about that). For the sake of simplicity in this example, we will make the controls public so that one form has no problems directly accessing a control on another form (more about this later). Bring up the property sheet for your main form, and check the 'ControlsPublic' check box at the bottom of the General page. Now do the same thing for your tab form.
Our mission in this example is to have it so that if we type stuff into one textbox, the other one will update to reflect the changes. Start by handling the Change event of the textbox on your main form. Right-click on textb_Main and choose Change from the Events sub-menu. Now add the following code to the event:
WString newText, oldText;
newText = textb_Main->GetText(); if( newText != oldText ) {
oldText = _TabForm1->textb_Tab->GetText();
_TabForm1->textb_Tab->SetText( newText );
}
"But where did that thingie with the underscore come from," you exclaim. Well, you won't see it unless you tell Power++ to show you all the code that it generates automatically (choose Options from the Tools menu and check the box 'Show generated code'), but Power++ will always give you pointers to your different tab forms, which are just the names of the tab forms with an underscore before them. So if you had a public user function on that tab form, you could do something like the following from your main form:
_TabForm1->MyCoolPublicFunction( someData, someMore );
To go the other way around - sending data from the tab form to
the main form - requires only slightly more work. First we need
to let the tab form 'see' the main form's class, and to do that
we must include the main form's header file, by adding the following
line to the section of the tab form's code window that says, "code
added here will be included at the top of the .CPP file":
#include "FormMain.hpp"
Now, if you try to compile your program like this, you will probably
get an error saying, "unable to open FormMain.hpp," or something
to that effect. This is because when you renamed the main form
from Form1 to FormMain, you only renamed the class, and not the
file it was stored in. You can just change the include line to reflect the old file name (Form1.hpp), but to make thing
a little neater you can rename the file (you see, you're getting
two tips for the price of one this week). Bring up the Class View
by choosing Classes from the View menu, right-click on FormMain,
and choose Properties. Now you can change the file name to reflect
the class name. And finally, right-click on the text box on the
tab form and choose Change from the Events popup menu to handle
that event, and add the following code:
WString oldText, newText; form_Main = (FormMain *) GetParent(); newText = textb_Tab->GetText(); if( oldText != newText ) {
FormMain * form_Main;
WASSERT( form_Main != NULL );
oldText = form_Main->textb_Main->GetText();
form_Main->textb_Main->SetText( newText );
}
The two bolded lines represent the main difference between this and the other handler. Here we must get the pointer to the main form (which is the parent of the tab form we are on) by ourselves. Notice that the GetParent method is cast to the correct type (FormMain *) since it returns a pointer to a WWindow which is not what we want. Run the program and try typing text into each of the text boxes... Fun! :)
Before people start flaming me, I should mention that it is not generally considered good coding practice to make the controls on a form public as we did. For a simple example like this, it might not be such a bad idea, but for anything non-trivial, it is recommended that you leave the controls protected on their forms. How then would you pass around data? Often the nicest way is to use an FDX structure (for tab controls, you'd make your own FDX structure and use it for each tab form - see the help for more information). But if you want to have more flexibility or your task is too simple to warrant using FDX, then you can still use the technique outlined above, but instead of directly accessing the controls, you would make public methods (user functions) that would be called using the same basic structure as the code above. For example, you might make a public method of the tab form that accepts a WString parameter and sets the text box in the tab form with that string that was passed to it. You could then call this public method from the main form, passing along the desired text...
Well I didn't realise this thing was going to get so long. Hope it helps some of you out! :)