Added TForms to TPageControl, how do I notify TForm that it is showing?

1.1k Views Asked by At

I have a TPageControl with a number of TTabSheets that contain TForms (or possibly TFrames, but TForms for now).

When a tab comes into view I would like the TForm or TFrame to be notified it has come to the front. I can't find anything that does that.

I know I can get the Active TTabSheet in the OnChange event, so I tried to add this class to the TForm:

struct iTab
{
    virtual void DoIt( void ) = 0;
};

with the this in the OnChange:

  ICPTab *tab = dynamic_cast<ICPTab *>( sheet->Controls[ 0 ] );

Thinking I could use RTTI to get the iTab pointer and call DoIt() from the And I get the warning:

[BCC32 Warning] Unit1.h(18): W8130 Interface 'IPTab' does not derive from IUnknown. (Interfaces should derive from IUnknown) 
[BCC32 Warning] MainWindow.cpp(612): W8131 Casting Delphi style class 'TControl' to an interface. Use 'System::interface_cast<ICPTab>(cls)' instead

I am not interested in getting all of IUnknown just so that the form can use an interface.

I can get the TFrame or TForm pointer using:

  TForm *tab = dynamic_cast<TForm *>( sheet->Controls[ 0 ] );

but can't call a non TForm method with this pointer. Would it be ok to call the Activate() method?

So how do I notify the TForm or TFrame that it is now showing?

2

There are 2 best solutions below

1
On BEST ANSWER

I went with the following code:

  void __fastcall TgMainWindow::mPageControlChange( TObject* Sender )
  {
     NOT_USED( Sender );
     TTabSheet* sheet = mPageControl->ActivePage;

     if ( sheet->ControlCount > 0 )
     {
        // form or frame, we will attempt to call the OnActivate method
        TForm* form = dynamic_cast<TForm *>( sheet->Controls[ 0 ] );

        if ( form == NULL )
        {
           ShowMessageDlg( this, L"Programming Error: Initial child on tabsheet must be a TForm", mtError, TMsgDlgButtons( ) << mbOK );
        }
        else
        {
           if ( form->OnActivate != NULL )
           {
              form->OnActivate( this );
           }
           else
           {
              ShowMessageDlg( this, L"Programming Error: From must have an OnActivate event", mtError, TMsgDlgButtons( ) << mbOK );
           }
        }
     }
  }

Since a form on a tabsheet never has its OnActivate method called, this works quite well.

note: the method sample is not complete, there is no call to OnDeactivate

2
On

You have to derive iTab from IUnknown (or IInterface) or order to use it as an interface correctly. The compiler warning even hints that you can use interface_cast to extract an interface from a Delphi-style (aka TObject-derived) object. Alternatively use TObject::GetInterface() instead.

Otherwise, if you just want to call methods of your custom TForm class, then just type-cast the child control pointer from your TTabSheet to your actual TForm-derived class:

TMyForm *tab = dynamic_cast<TMyForm *>( sheet->Controls[ 0 ] );
if( tab != NULL ) tab->DoSomething();

Or:

static_cast<TMyForm *>( sheet->Controls[ 0 ] )->DoSomething();