contents   index   previous   next



Creating the CMain ActiveX component

 

This is by far the most complex object in this project, because the CMain object will act as the main window of our application and also generates events. Start by adding a new form to the Visual Basic project f90VBGUI. Change the name of the form to FormMain and set its caption text to “f90VB GUI Demo”. Add a MSFlexGrid control to the form. If the MSFlexGrid is not in your IDE’s tool bar, you need to add the component to the project. To do this click on Project on the IDE’s menu bar, select Components, find MSFlexGrid in the list that pops up and check-mark the MSFlexGrid ActiveX control.

 

Now right-click anywhere in the form and select the Menu Editor option from the pop-up menu. This opens the menu editor that you use to add a menu bar to your form. Create a menu structure similar to the one shown in Figure 13. The names of the top menu items can be anything you want, but we need to agree on specific names for lower-level items, because they generate events that must be handled in the form. The table below shows the names you should assign to these menu items:

 

Caption of the menu item Name of the menu item
&Exit mnuFileExit
&Logs Table… mnuToolsLogs
&Factorials Table mnuToolsFactorials
&Excel chart mnuToolsExcelChart
&About f90VB Demo mnuAboutAbout

Now add the code in Sample Code 11 to the form. You might have noticed that we add five public events to the form:

 

Public Event OnExitClick(Cancel As Integer)

Public Event OnLogTableClick()

Public Event OnFactorialTableClick()

Public Event OnAboutBoxClick()

Public Event OnExcelChartClick()

 

We do this because the events generated by controls contained inside a form do not bubble-up the form. Normally none of these events will be seen by a class containing a reference to the form, even if the form doesn’t explicitly handle the events fired by the controls. Defining new events at the form level, we create a mechanism to bubble-up events generated by the controls contained by the form. Better yet, we can bubble-up only those events we want to see in the main program.

 

Let’s take a more detailed look of how the bubbling-up of events works. The form’s menu bar has a Tools/Logs Table option. When the user clicks on this option, the menu control generates the event mnuToolsLogs_Click. When the form receives this event, it raises its own OnLogTableClick event:

 

Private Sub mnuToolsLogs_Click()

    'Fires (bubbles up) OnLogTableClick event

    RaiseEvent OnLogTableClick

End Sub

 

Because OnLogTableClick is a public form-level event, this event can be seen by a class that contains an instance of the form that has been declared with the WithEvents modifier.

As you can see, most of the code we have added to FormMain just bubbles-up the menu selection events that we want to see outside the form.

 

Now that we are done with the form, let’s see class CMain, which wraps form FormMain into an ActiveX object (Sample Code 12). Class CMain has a private variable that contains a reference to a FormMain form:

 

Private WithEvents TheForm As FormMain

 

Notice that the variable is declared with the WithEvents option, so events fired by the form are seen by the class.

 

The class initialization sets the value of private variable TheForm to a new instance of MainForm:

 

Private Sub Class_Initialize()

    Set TheForm = New FormMain

End Sub

 

The class termination code sets TheForm to nothing, closing and unloading the instance of FormMain when the class is terminated.

 

Class CMain also has two public methods (Show and Hide) and one property (fgTable). What the methods do is completely obvious, they either show or hide the form wrapped by the class. Property fgTable is a read-only property:

 

Public Property Get fgTable() As Object

    Set fgTable = TheForm.MSFlexGrid1

End Property

 

This property is used to expose the MSFlexGrid control contained by FormMain. This way the contents of the control can be changed by an application that instantiates the CMain class. Because the property is read-only, the application containing CMain gets access to the properties and methods of the MSFlexGrid control, but it can’t replace or remove the control from the form.

 

You also might have noticed that CMain declares five events:

 

Public Event OnQuit(Cancel As Integer)

Public Event OnLogTableClick()

Public Event OnFactorialTableClick()

Public Event OnAboutBoxClick()

Public Event OnExcelChartClick()

 

These events are fired when the corresponding FormMain events are fired. In other words, the class bubbles-up the form’s events to the client application. What we have done here is to bubble-up events fired by form’s controls all the way up to the application level. This way we have the opportunity to handle these events in our Fortran application.

 

An important detail to notice in class CMain is that method Show displays FormMain as a modeless form. This is much more important that it may seem at first sight. Class CMain bubbles-up some of the events fired by the FormMain. As you’ll see later, these events are then handled by a subroutine in the main Fortran application. If CMain showed FormMain as a modal form, the f90VB call to execute method CMain.Show (function ExecMethod) would not return control to the main program until FormMain is closed. This by itself is not a problem since the events fired by CMain will still be processed by the appropriate Fortran event handler. The problem arises if and when we make another call to ExecMethod inside the event handler. Because the first call (i.e. the one to CMain.Show) has not finished executing, the second call will re-enter subroutine ExecMethod, corrupting the data from the first call. Of course this can easily be avoided by ensuring that both calls are made from different threads, but we will leave this technique for a more advanced tutorial. For now, as a rule of thumb, forms that are sources of events should always be shown as modeless forms. However, this creates another problem; Visual Basic would only let you show modeless forms in an ActiveX DLL if the ActiveX is instantiated by another Visual Basic application. In other words, we cannot use modeless forms in a Visual Basic ActiveX DLL from Fortran. The solution to this problem is simple, although perhaps not optimal; compile the ActiveX server as an out-of-process server (i.e. as an ActiveX executable).


Converting your Visual Basic Project into an ActiveX EXE