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 answers

1
Gregor Brandt 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
Remy Lebeau 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();