Search code examples
excelvbavariablescontrolsuserform

Excel VBA How to convert multiple controls and variables into a universal function


I have a -userform- that has 100 different controls (Textbox and combobox) and i am trying to consolidate one large chunk of code down to something smaller and universal... by basing it on the active control and using that as my reference point for calling another sub where the declared variables will become plug and play.

So here is the base code that works... But i would need to replicate this 25 times and I feel like there is a better way, but i cannot seem to figure it out...

Option Explicit

Public Gal, Kg, L, Qt, Pt, Lbs, C, FlOz, Ea, Prts, Oz, Tbs, Tsp, Dl, G, Ml As Integer

Private Sub M1_AfterUpdate() 'this is where the math happens

'I have 25 variables, M1:M25 -  by 16 variables, Gal:Ml for each

Gal = 128: Kg = 35.274: L = 33.814: Qt = 32: Pt = 16: Lbs = 16: C = 8 'multiply
FlOz = 1: Ea = 1: Prts = 1: Oz = 1 'stay
Tbs = 2: Tsp = 6: Dl = 3.381: G = 28.353: Ml = 29.574 'divide

'this is the base code that does ecactly what I need... But i would have to replicate this whole thing 25 times...

    If ActiveControl.Text = "Gal" Then C1.Value = Round(((Q1 * Gal) * (Application.WorksheetFunction.Index(Sheets("Inventory").Range("C6:L1006"), _
                                                Application.WorksheetFunction.Match(I1, Sheets("Inventory").Range("C6:C1006"), 0), 10))), 2)

    If ActiveControl.Text = "Kg" Then C1.Value = Round(((Q1 * Kg) * (Application.WorksheetFunction.Index(Sheets("Inventory").Range("C6:L1006"), _
                                                Application.WorksheetFunction.Match(I1, Sheets("Inventory").Range("C6:C1006"), 0), 10))), 2)

    If ActiveControl.Text = "L" Then C1.Value = Round(((Q1 * L) * (Application.WorksheetFunction.Index(Sheets("Inventory").Range("C6:L1006"), _
                                                Application.WorksheetFunction.Match(I1, Sheets("Inventory").Range("C6:C1006"), 0), 10))), 2)

' it goes on through each of the variables but i post it all, you get the idea ; )

End Sub

I have tried this road...THIS WAS A FAIL!!! I couldn't figure how to read it as a control name, it read as string.

I tried putting contol / controls in the front and that didnt work...

Option Explicit

Public Gal, Kg, L, Qt, Pt, Lbs, C, FlOz, Ea, Prts, Oz, Tbs, Tsp, Dl, G, Ml As Integer

Private Sub M1_AfterUpdate() 'this is where the math happens
Dim ActCtrl As Control: Set ActCtrl = ActiveControl.Name
Dim VarA As Integer
Dim x, y, z As String

If ActCtrl = M1 Then VarA = 1 ' 25 if lines written to represent 25 rows of form controls
'M2 is VarA=2 and so on till 25

'this puts them together, but it returns string.
    x = "I" & VarA
    y = "Q" & VarA
    z = "C" & VarA

    'this is where it would end
    z.Value = Round(((y * Ml) * (Application.WorksheetFunction.Index(Sheets("Inventory").Range("C6:L1006"), _
                                Application.WorksheetFunction.Match(x, Sheets("Inventory").Range("C6:C1006"), 0), 10))), 2)

I would like to be able to change this...

    If ActiveControl.Text = "Gal" Then C1.Value = Round(((Q1 * Gal) * (Application.WorksheetFunction.Index(Sheets("Inventory").Range("C6:L1006"), _
                                                Application.WorksheetFunction.Match(I1, Sheets("Inventory").Range("C6:C1006"), 0), 10))), 2)

into a plug and play using variables... If possible...


Solution

  • Create a two-column lookup table on a sheet, with Unit & Conversion Factor, and use vlookup to directly convert the units to the scaling value.

    Then factor almost all of the code out of your M1_AfterUpdate into generic methods to which you can just pass M1 etc.

    Something along these lines:

    Private Sub M1_AfterUpdate() 
        HandleCombo M1 
    End Sub
    
    Private Sub M2_AfterUpdate() 
        HandleCombo M2 
    End Sub
    'etc for other combos
    
    
    'handle a combo box changing
    Sub HandleCombo(cmbo)
        Dim f, c as object
        f = GetScalingFactor(cmbo.Text)
        Set c = me.Controls(Replace(cmbo.Name, "M", "C")) 'corresponding text control
        c.Value = 'long formula which uses f
    End Sub
    
    'convert unit to scaling factor
    Function GetScalingFactor(unit)
        Dim m, rv
        m = Application.Vlookup(unit, _
                                thisworkbook.sheets("lookup").Range("A2:B26"), _
                                2, False)
        If not iserror(m) then
            rv = m
        else
            'no match on the unit name - what to do here?
            rv = -1 'or raise an error
        end if
        GetScalingFactor = rv
    End function