Breakthrough
              in the Pseudo-Control-Array

[ back to Bpca ]
      ( Because I who am poor at English am translating into English while using translation software,  
        there may be an odd expression. The mistranslation revises it sequentially. )

Focus class (clsBpcaFocus / clsBpcaFocusCh)
  (Jpn. 1st Edition : 1 Jun. 2004 )
  (Jpn. Last Edition : 22 Jul. 2014 )
  (Eng. Translation: 4 Oct. 2016 )


--- I want to highlight the control with the focus. ---
It is a question to hear well.
This can be realized by processing "to emphasize it by Enter event, and to remove emphasis by Exit event".

Therefore it is necessary to describe processing for Enter/Exit events of all control on UserForm.

This has much waste as both quantity of coding and efficiency.
If Enter/Exit events are unified by a class module, this waste will dissolve.
However, unfortunately it cannot catch Enter/Exit events in the class module.
( Note : It can catch Enter/Exit events in a class module now by using ConnectToConnectionPoint API.
           This article wrote it before finding a method using ConnectToConnectionPoint API. )


Because it cannot unify Enter/Exit events in a class module, methods using an ENDLESS LOOP are
introduced well instead. It continuously monitor a change of ActiveControl with the ENDLESS LOOP
in the class module. And it fire a custom event by RaiseEvent if it has a change.



Here, I will review this "focus monitoring" problem once again.
Q1: Why is continuously monitoring it necessary?
A1: When does a focus move to where from where?
      Because I do not know it, continuously monitoring it is necessary.

Q2: But does focus movement not occur without permission?
A2: It is the following cases that it occurs.
      (1) Key operation ( Tab , Enter , Access-key )
      (2) Mouse Click
      (3) SetFocus method

Q3: As for (1) & (2), KeyDown/Up, MouseDown/Up events occur.
      As for (3), "At this time now" is self-evident on a macro side.
      Then only by checking whether ActiveControl changes at time?

A3: (3) does not have any problem.
      But (1) & (2) must prepare for an event for all the control.
      Then I will return to the first problem.
       ( This has much waste as both quantity of coding and efficiency. ).

Q4: Should you unify events using a class module?
A4: There is not means to notify UserForm of detected focus movement.

Q5: Should you use RaiseEvent?
A5: It becomes the class object array to settle much control.
      In that case, it cannot describe WithEvents definition to receive a notice
      of RaiseEvent on the UserForm module ( specifications of WithEvents ).

The dilemma of this problem is such a thing.
However, the problem dissolves if you apply technique of clsBpca.

The class module which I made in this way is clsBpcaFocus.

Private WithEvents FocusCtrl As clsBpcaFocus

Private Sub FocusCtrl_GotFocus(ByVal Index As Integer)
    FocusCtrl.Item(Index).BackColor = &HAAAAFF      'Light Red
End Sub

Private Sub FocusCtrl_LostFocus(ByVal Index As Integer)
    With FocusCtrl
        'It goes back up in an initial background color by [InitBColor] property.
        'The initial background color is stored at the time of
        'the registration of the clsBpcaFocus class.

        .Item(Index).BackColor = .InitBColor(Index)
    End With
End Sub



[ Structure of focus detection class ( clsBpcaFocus ) ]
About the following controls that are input controls among MsForms control,
      CommandButton, TextBox, ComboBox, ListBox, CheckBox
      OptionButton, ToggleButton, SpinButton, ScrollBar

it check ActiveControl by KeyDown/KeyUp/MouseDown/MouseUp events and
it fire GotFocus/LostFocus events depending on a change of ActiveControl.
( Because SpinButton and ScrollBar do not have MouseDown/Up, it substitute it in SpinDown/Up and Change ).
In addition, it supports Frame ,MutiPage, TabStrip.

( Note 1 )
      A reaction seems to be late in SpinButton and ScrollBar.
      In addition, it seem to rarely miss LostFocus of ScrollBar when it come and go by Mouse-Click
      between SpinButton and ScrollBar.
      It is having highlights for a background color of ScrollBar, and SpinButton may be highlighted together, too.

( Note 2 )
      When it perform [ Cancel = True ] of the BeforeUpdate event in the case of Tab/Enter pressing in TextBox ( last
      tab order ) in Frame/MutiPage, it becomes the strange state ( the following ).
      The cursor stay in TextBox, nevertheless focus highlights move to the next control of Frame/MutiPage.
      This is not malfunction by the clsBpcaFocus class. It is the malfunction that originally Frame/MultiPage has.
      ( It have attracted attention by the highlights of the focus. )

      You can confirm this symptom in sample macro as follows.
      (a)  It change tab order of TextBox4 in Frame1 to the last
      (b)  It add the following macro to UserForm module.
  Private Sub TextBox4_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
    If (TextBox4.Value = "a") Then
        Cancel = True
    End If
End Sub
      (c) With a test form, you input "a" into TextBox4 and push down Tab/Enter.
      (d) A cursor stay in TextBox4. Nevertheless highlights move to TextBox of MultiPage.
            Actually, ActiveControl of the UserForm level points at MultiPage1 and does not point to Frame1.





    [ Bpca_Focus_V15E.zip ]   ( 64 kb )      ( It works in x64. )
            Bpca_Focus_V15E.zip    ( Distribution file )
                +--  Bpca_Focus_V15E.xls      ( Class Definition and Sample Macro )
                +--  ExportV15E    ( Export file , Please import this file in your workbook. )
                            +--  clsBpcaFocus.cls
                            +--  clsBpcaFocusCh.cls

        If warning of "<file name> is not commonly downloaded and could be dangerous"
        is given by the downloading of the file, ....  

        1 Jun. 2004    Ver 1.0    1st version (Japanese)
        22  Jul.  2014      Ver 1.5        (Japanese)
        4  Oct.  2016      Ver 1.5        English 1st version


(1) It is necessary to take 2 following modules in workbook by import from
     a distribution file to use this class.
        (a) clsBpcaFocus  
        (b) clsBpcaFocusCh

        When you copy a class module in workbook,
                please perform it by Import by all means.
        If you perform it by "Copy & Paste" between code windows of VBE ,
                Item property does not become "Default Property"( See below )

(2) clsBpcaFocusCh class is a lower class of the clsBpcaFocus class (a user cannot use
     directly this class).

(3) This class is available Excel2000 and later. (It works in x64.)



[ Link to here ]

[ Reference of Event / Method / Property ]

Within the following description, the object variable which defined clsBpcaFocus
class is described into the portion of "object".



[ Definition ]

    It defines by the declaration section (module head) of a UserForm module as follows.

          Private  WithEvents  object  As  clsBpcaFocus

    You can define plural if you change "object".

    ( object )
        Specify arbitrary names.
        In "Initialize" event procedure, the instance of a class is created as follows.

            Set  object  =  New  clsBpcaFocus



[ Method ]

    object .Add    MsForms Control object

    Method to register Control objects making Control-Array with clsBpcaFocus class.
    You repeat "Add" method for controls to become one group and register by "Rgst" method last.

    A control number is assigned to the order that you registered by Add method from 1.
    This number is treated in each Event or Property as Index.

    ( MsForms Control object )
        Specify a control object making Control-Array.

    It register all control from Me.Controls collection in For Each statement (please refer to a use example).
    Because it exclude the non-input control (Label etc.) in a class, please add all control without minding input/non-input control.


    object .Rgst    Form

    Method to generate Control-Array from the controls that you added by Add method.
    After having repeated Add method, you carry out Rgst method.

    ( Form )
        It appoint own UserForm. Please really describe Me keyword.


    object .Clear

    Method to perform the release of the class object.
    Always carry it out by Terminate event of UserForm.


    object .FocusCheck

    This is a method to fire LostFocus/GotFocus events when ActiveControl changes.
    It is a method used in clsBpcaFocusCh, but uses even the UserForm side.

    It use FocusCheck method in the following of the UserForm module.
    (1)  Please describe it in UserForm_Activate to get an initial focus position.
    (2)  Please describe FocusCheck method just after SetFocus method.
    (3) When you place control except MsForms (e.g. RefEdit),
          please describe FocusCheck method for Enter event of the control.


[ Property ]

    object .Count    [ = Integer ]

    Property to acquire the number of controls registered with Toggle-Label-Button of "object".
    [ Read only ]

    ( Getting )
        Return numerical value for the number of controls that you registered by Add method.
        This value is the maximum of "Control Number".


    object .getIndex ( CtrlName )    [ = Integer ]

    Property to acquire the value of Index (position number registered in collection) corresponding to
    the control name from a control object registered with Control-Array of "object".
    [ Read only ]

    ( CtrlName )
        Appoint a control name by string.

    ( Getting )
        It returns a value of "Index" becoming necessary for each property from a control name.
        In the case of a non-registration name, it returns minus 1.


    object .Item ( Index )    [ = Objectl ]          ---- Default Property ----

    Property to return individual control objects constituting Control-Array of object.
    [ Read only ]

    (Note)
        Read-Only is a limit about the reference to the control object.
        It is not a meaning "not to be able to update each property" of the control object.


    It is property to acquire the control object when you operate individual control of Control-Array.
    You can describe the individual propertys of the object across the period after Item property.
          example :   object .Item (1) .BackColor


    Because Item property is defined as Default-Property ,
    you can omit ".Item" and can describe as follows.      ( Q & A )

          example :   object (1) .BackColor


    ( Index )
        Appoint a control number (in the order that you added by Add method consecutive numbers
        from 1). You can appoint it by a control name if you use getIndex property together.

    ( Getting )
        The control object of the number that you appointed in Index argument returns with a general-purpose Object type.
        If the number that you appointed is out of a range (1 to object.Count), it return Nothing as an error.



    object .InitBColor ( [Index] )    [ = Long ]

    Property to return Initial-Background-Color of the control object.
    (The value of the BackColor property stored for Add/Rgst method run time)
    [ Read  only ]

    Please use it for the return to Initial-Background-Color by LostFocus event.
      Private Sub FocusCtrl_LostFocus(ByVal Index As Integer)
        With FocusCtrl
            .Item(Index).BackColor = .InitBColor(Index)
        End With


    ( Index )
        Appoint a control number (in the order that you added by Add method consecutive numbers
        from 1). You can appoint it by a control name if you use getIndex property together.

    ( Getting )
        Initial-Background-Color of the control object of the number that you appointed in Index argument returns.
        If the number that you appointed is out of a range (1 to object.Count), it return -1 (minus one).


[ Event ]

    Private Sub object_GotFocus ( ByVal  Index  As  Integer )
    Private Sub object_LostFocus ( ByVal  Index  As  Integer )

    When a focus moved, it fire.

    (  Index  )
        A number of the control (in the order that you added by Add method consecutive numbers from 1)
        that an event fired returns.

    -- Highlights of the focus --
    Please change a background color of the control in GotFocus,
    and go back up in an Initial-Background-Color using InitBColor property in LostFocus.


[ Q & A ]

      (a) The omission of the Item property becomes the error.
            (Symptom)
                  The following description that omitted Item property becomes the error.
                          ex.  FocusCtrl(Index).BackColor
                  It does not become the error if I describe Item property.
                          FocusCtrl.Item(Index).BackColor

      --- Answer ---
            (Cause)
                  You performed "copy & paste" of clsBpcaFocus class module between code windows of VBE.

            (Answering measure)
                  Please delete clsBpcaTglLbl class module by "Free module".
                  Thereafter, please import from export file (clsBpcaFocus.cls) in the distribution file.

            (Explanation)
                  Attribute statement (it is invisible on the code window) is written in at the procedure
                  of Item property (it is visible on the export file).
                  The Attribute statement lacks when you copy a class module by "copy & paste".
                  As a result, Default property does not work.


[ Link to here ]

[ Usage example ]




 Private WithEvents FocusCtrl As clsBpcaFocus
 Private blnFormClose As Boolean


 Private Sub UserForm_Initialize()
 Dim objCtrl As Object
 Dim i As Integer

   Set FocusCtrl = New clsBpcaFocus

   'All the control in Frame1/MutiPage1 is registered by Me.Controls, too.
   'The inapplicable control such as RefEdit/Label are removed in a class.

   For Each objCtrl In Me.Controls
       FocusCtrl.Add objCtrl
   Next objCtrl

   FocusCtrl.Rgst Me    'Registration to clsBpcaFocus

   ListBox1.List() = Array("111", "222", "333", "444", "555")
   ListBox2.List() = Array("AAA", "BBB", "CCC", "DDD", "EEE")
   ComboBox1.List() = Array("111", "222", "333", "444", "555")
   ComboBox2.List() = Array("AAA", "BBB", "CCC", "DDD", "EEE")
   ComboBox3.List() = Array("111", "222", "333", "444", "555")
   ComboBox4.List() = Array("AAA", "BBB", "CCC", "DDD", "EEE")
 End Sub


 Private Sub UserForm_Activate()
   'It acquire an initial focus position by carrying out [FocusCheck]
   'just after Show method.

   FocusCtrl.FocusCheck
 End Sub


 Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
   blnFormClose = True
 End Sub


 Private Sub UserForm_Terminate()
   FocusCtrl.Clear
   Set FocusCtrl = Nothing
 End Sub


 '=========================================================
 '   The event by clsBpcaFocus is GotFocus and LostFocus.
 '=========================================================

 Private Sub FocusCtrl_GotFocus(ByVal Index As Integer)
   FocusCtrl.Item(Index).BackColor = &HAAAAFF    'Light Red
 End Sub


 Private Sub FocusCtrl_LostFocus(ByVal Index As Integer)
   'It goes back up in an initial background color by [InitBColor] property.
   'The initial background color is stored at the time of
   'the registration of the clsBpcaFocus class.

   With FocusCtrl
       .Item(Index).BackColor = .InitBColor(Index)

       'If a value of TextBox is a number, it edit a comma.
       If (TypeName(.Item(Index)) = "TextBox") Then
           If (.Item(Index).Value = "") Then
               'Nothing
           ElseIf IsNumeric(.Item(Index).Value) Then
               .Item(Index).Value = Format(CDbl(.Item(Index).Value), "#,##0")
           Else
               'Not Numeric
           End If
       End If
   End With
 End Sub


 'Coexistence test with the Cancel processing by the normal Exit event
 Private Sub TextBox1_Exit(ByVal Cancel As MsForms.ReturnBoolean)
   If (blnFormClose = True) Then
       'As it is the userform end, it do not check a value.
       Exit Sub
   End If

   If (TextBox1.Value <> "") Then
       If IsNumeric(TextBox1.Value) Then
           'OK
       Else
           Cancel = True
           Beep
       End If
   End If
 End Sub


 Private Sub CommandButton1_Click()
 'After carrying out SetFocus, it always carry out [FocusCheck].
   TextBox3.SetFocus
   FocusCtrl.FocusCheck
 End Sub


 Private Sub CommandButton2_Click()
 'After carrying out SetFocus, it always carry out [FocusCheck].
   TextBox4.SetFocus
   FocusCtrl.FocusCheck
 End Sub


 '== About the outside control targeted for clsBpcaFocus,
 '== it change a background color by Enter/Exit event of each control.

 Private Sub RefEdit1_Enter()
 'About the outside control targeted for clsBpcaFocus,
 'it always carry out [FocusCheck] by Enter event.

   FocusCtrl.FocusCheck
   RefEdit1.BackColor = &HAAAAFF    'Light Red
 End Sub


 Private Sub RefEdit1_Exit(ByVal Cancel As MsForms.ReturnBoolean)
   RefEdit1.BackColor = vbWindowBackground
 End Sub




[ AddinBox Home (Japanese) ]  [ English Home ]  [ back to Bpca ]  


AddinBox ( K.Tsunoda in Japan ) CopyRight(C) 2016 Allrights Reserved.