|
As it turns out, you can uncheck the Default Form choice on the form that is currently default, and everything will work perfectly... until you save and then reload your program. At that time, the form that had been default regains that position, and -- this is the biggie -- your ApplicationClass is regenerated and you lose all changes you have made to it. This took away quite a few hours of work from me, but my loss is your gain. :) The solution is pretty simple. If you don't want any form to load by default, go to the ApplicationClass and return true (instead of false) in both the StartHandler and the EndHandler... This will prevent the default form from being created and destroyed. When you want to close your application from a form, you will have to call AppObject.Quit();. See the Contact Screen Saver example, on the Power++ Code page for an example of all this. The moral of the story here is to backup any changes you make to your ApplicationClass... Just in case.
I know it's come up several times about how to check a tabcontrol's tab forms for errors or incomplete data but doing it all at once in the tabcontrol's OK event handler means making controls or data public in the pages. I've been using LostFocus events for the control checking on pages but found that if I'm in the middle of filling in a tab form and decide to change to another program (e.g. Explorer), I get a lost focus and an error that I don't need if I'm not finished.
Since I discovered a while ago that tabcontrol pages do NOT receive an OK event (but it is defined for tab page forms so its use I haven't seen yet), I found the following nice trick for letting all of your tab forms check themselves and prevent the tabcontrol dialogue from closing if there's an error or other reason.
In my tabcontrol OK event handler I have:
WBool tabControl::OkButton_Click(
WObject * source,
WEventData * event )
{
WShort count;
WInt i;
WModelessDialog * form;
count = tabctrl_1->GetCount();
for( i = 0; i < count; i++ ) {
form = (WModelessDialog *)tabctrl_1->GetWindow( i );
if( form->CallEventHandler( WOKEvent, NULL ) ) {
tabctrl_1->SetSelected( i );
return true;
}
}
for( i = 0; i < count; i++ ) {
form = (WModelessDialog *)tabctrl_1->GetWindow( i );
form->FDXUpdateControls();
}
FDXUpdateControls();
Dismiss( TRUE );
return FALSE;
}
In tab pages that need it, I handle the OK event and do my error checking. If the OK handler returns true, the dialogue is not exited. And this selects the tab page with the first error so the user can make a change.
Place a command button on a form along with a label and a picture box. Give the command button and the label some text, and give the picture box an image (the default icon resource is fine). Now run the program and click on the button to give it focus (if it doesn't already have it). Now if you were to click on either the picture box, or the label, you will notice that it steals away the focus partially from the command button and you are left with only a thin grey rectangle. This should never happen. The solution is to turn off the Notify style for both the label and the picture box (it should really be off by default). For the label, this is a simple matter of unchecking the Notify check box on the Advanced Style page of its property sheet. For the picture box there is no such design-time property, so you must add a line of code such as:
pictb_1->ChangeStyle( WSSNotify, false );
for each picture box, in the Create event of the form which contains them. Note that this problem occurs not only with the label and the picture box, but also with WToolbar, WGauge, SFaceBox, WVScrollBar, WHScrollBar, WProgressBar, WHSplitBar, WVSplitBar, and WStatusBar, but these controls do not possess a Notify style, and I have not been able to determine how to get rid of the behaviour with them. If you do, please let me know! Speaking of writing me... if you don't write in tips, I can't post them. :)
The KeyDown events get sent to the combobox's edit control. So
we'll create a class derived from WTextBox that will represent
the edit control. This class, called MyComboTextBox here, will
subclass the edit control window and receive its events. Then
in the form that needs to process the KeyDown event, create an
instance of MyComboTextBox in the Create event (after the combobox
has been created) and setup your WKeyDownEvent event handler.
Note, the class uses the Windows API go the a handle to the edit
control. You'll need to edit your precompliled header to use the
API. Here is what your new class derived from WTextBox should
look like:
// ====================================================================
// MyComboTextBox class:
// ====================================================================
class __MyComboTextBox_declspec MyComboTextBox : public WTextBox
{
// Macro used to override class identification methods
WDeclareSubclass( MyComboTextBox, WTextBox );
private:
// Default Constructor: made private to prevent use.
//
MyComboTextBox();
public:
~MyComboTextBox();
public:
// Primary Constructor: Attaches this object to the edit
// control of a combobox
//
MyComboTextBox( WComboBox* parent );
};
// Code added here will be included at the top of the .CPP file
#include "WRes.h"
// Macro used to define overridden class identification methods
WDefineSubclass( MyComboTextBox, WTextBox );
MyComboTextBox::MyComboTextBox()
{
}
MyComboTextBox::~MyComboTextBox()
{
// Cleanup: reverses our subclassing...
//
DetachFromWindow();
}
MyComboTextBox::MyComboTextBox( WComboBox* parent )
{
// Get a handle to the edit control which is a child of the
combobox
//
HWND hWnd = ::GetWindow( (HWND)parent->GetHandle(), GW_CHILD
);
WASSERTEX( hWnd, "No parent window handle" );
if (hWnd) {
WBool destroy = FALSE; // don't destroy the HWND when
we delete.
WBool subclass = TRUE; // subclass the window to receive
events.
// Attach the edit control window to this object
// Don't call Create... the window already exists!
//
WBool attached = AttachToWindow( (WWindowHandle)hWnd,
destroy, subclass );
WASSERTEX( attached, "AttachToWindow failed");
// Can also establish event handlers here...
}
}
Your form's code should look something like this:
// ======================================================================
// Form1 class
// ======================================================================
#include "MyComboTextBox.hpp"
class __Form1_declspec Form1 : public __Form1_Base
{
private:
// Alias to a combobox's edit control
//
MyComboTextBox* comboTextBox;
public:
// comboTextBox_KeyDown event handler (User Function)
//
WBool comboTextBox_KeyDown( WObject* object,
WKeyPressEventData* event
);
};
// Code added here will be included at the top of the .CPP file
#include "WRes.h"
WBool Form1::Form1_Create(
WObject * source,
WCreateEventData * event )
{
// Create an alias for the combobox's edit control
// and establish event handler(s) for it.
//
comboTextBox = new MyComboTextBox( combo_1 );
comboTextBox->SetEventHandler( WKeyDownEvent, this,
WEventHandlerCast(Form1, comboTextBox_KeyDown)
);
return FALSE;
}
Form1::Form1()
: comboTextBox( 0 )
{
}
Form1::~Form1()
{
delete comboTextBox;
}
WBool Form1::comboTextBox_KeyDown( WObject * object, WKeyPressEventData
* event )
{
WString msg;
msg.Sprintf( "Key: %d", event->key );
WDBG(( msg ));
return FALSE;
}