How to use a Variable in different a Userform/module

bcmk29

Board Regular
Joined
Oct 20, 2022
Messages
55
Office Version
  1. 365
Platform
  1. Windows
  2. MacOS
I've got 2 different UserForms (UserForm & DataMap) with multiple modules in them.

1. Here's the code of my first Form UserForm. Where I'm allowing the user to select a spreadsheet and assign the file name to Importworkbook.

VBA Code:
Private Sub UserForm_Initialize()
'DataMap.Show vbModeless

    Dim LR, IB As Long
    Dim FileLocation As String
   
    Sheets("Input").Select
    Range("A1").Select
    Sheets("Sheet3").Range("R1").Value = 0
    file = ActiveWorkbook.Name
    LR = Cells(Rows.Count, 1).End(xlUp).Row
   
    If LR = 1 Then Else GoTo ok
   
        [B]FileLocation = Application.GetOpenFilename("(*.xlsx),")
       
        If FileLocation = "False" Then
            MsgBox "No file selected to import.", 48
            Unload Me
        Exit Sub
        End If
    End If
   
    Set Importworkbook = Workbooks.Open(Filename:=FileLocation)[/B]
   
    If Importworkbook.Sheets.Count > 1 Then
reIB:
        IB = Application.InputBox("Enter worksheet number", "Worksheet selection", , , , , , 1)
            If IB > Sheets.Count Then
                MsgBox "Invalid Sheet Input, Try Again.", 48, "Entry Required"
                GoTo reIB
            Else
                Sheets(IB).Select
            End If
            GoTo hi
    Else: End If
hi:
    ActiveSheet.Range("A1").Select
    Range(Selection, Selection.End(xlToRight)).Copy
    Workbooks(file).Activate
    Sheets("Sheet3").Select
    Range("P2").Select
        Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
        :=False, Transpose:=True
    Application.CutCopyMode = False
    Range("P1").Select
ok:
End Sub

2. Here's the code for my second Form DataMap, where I'm replicating the same set of codes from above. Instead, I just need to get the name of Importworkbook from my earlier code which is assigned in different userform/module. Please assist.

VBA Code:
Sub DataImport()
    Dim LR As Long
    Dim FileLocation As String
    Dim A, A1 As Integer
    LR = Cells(Rows.Count, 1).End(xlUp).Row
    If LR = 1 Then Else GoTo ok

[B]    FileLocation = Application.GetOpenFilename("(*.xlsx),")
    If FileLocation = "False" Then
        MsgBox "No file selected to import.", 48
        Exit Sub
    End If
    Set Importworkbook = Workbooks.Open(Filename:=FileLocation)[/B]

    ThisWorkbook.Worksheets(2).Activate
    SH = ThisWorkbook.Worksheets(4).Cells(Rows.Count, 19).End(xlUp).Row
For A = 2 To SH

'MsgBox DataMap!mastrImportworkbook
    Importworkbook.Worksheets(1).Range(Sheets("Sheet3").Range("T" & A).Value).Copy ThisWorkbook.Worksheets(2).Cells(1, A - 1)
Next A
    Application.ScreenUpdating = True
    ThisWorkbook.Worksheets(3).Range("A1:u1").Copy
    ThisWorkbook.Worksheets(2).Range("A1:u1").Select
    Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
        :=False, Transpose:=False
    Selection.PasteSpecial Paste:=xlPasteFormats, Operation:=xlNone, SkipBlanks _
        :=False, Transpose:=False
    Application.CutCopyMode = False
    Range("A1").Select
    Importworkbook.Close
    Application.ScreenUpdating = True

    ThisWorkbook.Worksheets(4).Select
    Range("P2").Select
    Range(Selection, Selection.End(xlDown)).Select
    Selection.ClearContents
    Range("S2").Select
    Range(Selection, Selection.End(xlDown)).Select
    Selection.ClearContents
    Range("R1").Select
    Selection.ClearContents
    ThisWorkbook.Worksheets(2).Select
    Range("A1").Select
ok:
   UserForm1.Show
End Sub
 
Hi bcmk29,

new modulewide Variables for the UserForm, Errorhandler added for all procedures.

UserForm_Initialize: filling of modulewide variables added, changed the array from getting the header names to getting both header names and column letter.
cmdAdd: shortened code to just work with UF from uploaded workbook
cmdProc: instead of using a dictionary which woud only allow unique items applied 2 arrays to hold the uniques and all headers. Maximum number of duplicates (not for single items but overall) as constant. Integrated check for the workbook with new data still to be opened.
DataImport: code slightly adapted for the use of column letter

Code behind the UserForm:

VBA Code:
Dim mstrFullNameWB    As String
Dim mstrNameWB        As String
Dim mstrNameWS        As String
'

Private Sub UserForm_Initialize()
  Dim lngIndexWS      As Long       'index of worksheet in new workbook if more than one worksheet
  Dim lngWS           As Long       'counter for index of worksheets in opened workbook
  Dim varFile         As Variant    'variable to hold path and filename for workbook to open
  Dim varArr()        As Variant    'values for the header values to be copied
  Dim strWS           As String     'Holding the names of worksheets of new workbook
  Dim ws              As Worksheet  'for looping worksheets in new workbook
  Dim wb              As Workbook   'for looping through all open workbooks
  Dim blnRunOnce      As Boolean    'boolean for getting information about worksheets,
  Dim blnUnload       As Boolean    'boolean whether to unload the UF
  Dim lngColMax       As Long
  Dim lngCounter      As Long
  Dim lngArr          As Long
  Dim strAddress      As String
 
  Const cstrProcName  As String = "UserForm1_Initialize"
  Const cblnBcmk      As Boolean = False
 
  On Error GoTo err_here
  blnUnload = False
  gblnCleanUp = True
 
  If tblInput.Cells(Rows.Count, 1).End(xlUp).Row <> 1 Then GoTo end_here
 
  If gwkbImport Is Nothing Then
    varFile = Application.GetOpenFilename("(*.xlsx),", MultiSelect:=False)
    If varFile = False Then
      MsgBox "No file selected to import.", 48
      blnUnload = True
      GoTo end_here
    End If
    Set gwkbImport = Workbooks.Open(Filename:=varFile)
  Else
    For Each wb In Workbooks
      If wb.Name = gwkbImport.Name Then Exit For
    Next wb
    Set gwkbImport = Workbooks.Open(Filename:=varFile)
  End If
  mstrFullNameWB = gwkbImport.FullName
  mstrNameWB = gwkbImport.Name
 
  If cblnBcmk Then MsgBox gwkbImport.FullName
  If gwsNewheader Is Nothing Then
    If gwkbImport.Worksheets.Count > 1 Then
      blnRunOnce = False
reIB:
      If blnRunOnce = False Then
        For Each ws In gwkbImport.Worksheets
          lngWS = lngWS + 1
          strWS = strWS & lngWS & " : " & ws.Name & vbCrLf
        Next ws
        blnRunOnce = True
      End If
      lngIndexWS = Application.InputBox("Enter worksheet number" & vbCrLf & Left(strWS, Len(strWS) - 1), "Worksheet selection", , , , , , 1)
      If lngIndexWS > gwkbImport.Worksheets.Count Then
        MsgBox "Invalid Worksheet Input, Try Again.", 48, "Entry Required"
        GoTo reIB
      ElseIf lngIndexWS = 0 Then
        MsgBox "Procedure cancelled", vbInformation, "Stopping here"
        gwkbImport.Close False
        Set gwkbImport = Nothing
        blnUnload = True
        GoTo end_here
      Else
        Set gwsNewheader = gwkbImport.Worksheets(lngIndexWS)
      End If
    Else
      Set gwsNewheader = gwkbImport.Worksheets(1)
    End If
  End If
  mstrNameWS = gwsNewheader.Name

  Err.Clear
  On Error GoTo 0
  If blnUnload = False Then
    tblAdmin.Range("P2:P" & tblAdmin.Rows.Count).ClearContents
    With gwsNewheader
      lngColMax = .Cells(1, Columns.Count).End(xlToLeft).Column
      lngArr = lngColMax - WorksheetFunction.CountBlank(.Range(.Cells(2, 1), .Cells(2, lngColMax)))
      ReDim varArr(1 To lngArr, 1 To 2)
      lngArr = 0
      For lngCounter = 1 To lngColMax
        If WorksheetFunction.CountBlank(.Range(.Cells(2, lngCounter), .Cells(4, lngCounter))) = 0 Then
          lngArr = lngArr + 1
          With .Cells(1, lngCounter)
            varArr(lngArr, 1) = .Value
            strAddress = Left(.Address(0, 0), Len(.Address(0, 0)) - 1)
            varArr(lngArr, 2) = strAddress '& ":" & strAddress
          End With
        End If
      Next lngCounter
    End With
    tblAdmin.Range("P2").Resize(UBound(varArr, 1), 2).Value = varArr
    Erase varArr
    Application.Goto tblAdmin.Range("P1"), True
  End If

end_here:
  Err.Clear
  On Error GoTo 0
  If blnUnload Then End
  Exit Sub

err_here:
  Debug.Print "Actual procedure name: " & cstrProcName & vbCrLf & _
              "Error number: " & Err.Number & vbCrLf & _
              "Error description: " & Err.Description
  Err.Clear
  On Error GoTo 0
  Resume end_here

End Sub

Private Sub UserForm_Activate()
  Dim rng2List        As Range          'object holding range for List for CBs
  Dim objCtrl         As Control        'object to cycle through the Controls on the UF
 
  Const cstrProcName  As String = "UserForm1_Activate"
 
  On Error GoTo err_here
  glngAddCtrls = 0
  Set rng2List = tblAdmin.Range("P2", tblAdmin.Cells(Rows.Count, 16).End(xlUp))
 
  For Each objCtrl In Me.Controls
    If TypeOf objCtrl Is MSForms.ComboBox Then
      objCtrl.List = rng2List.Value
      objCtrl.Style = 2
    End If
  Next objCtrl
 
  Application.Goto tblInput.Range("A1"), True
 
end_here:
  Set rng2List = Nothing
  On Error GoTo 0
  Exit Sub

err_here:
  Debug.Print "Actual procedure name: " & cstrProcName & vbCrLf & _
              "Error number: " & Err.Number & vbCrLf & _
              "Error description: " & Err.Description
  Err.Clear
  On Error GoTo 0
  Resume end_here
 
End Sub

Private Sub cmdAdd_Click()
  Dim objNewLB        As Object
  Dim objNewCB        As Object
  Dim lngUFHeight     As Long
  Dim lngLR_P         As Long
  Dim lngLR_U         As Long
 
  Const cstrProcName  As String = "cmdAdd_Click"
 
  On Error GoTo err_here
 
  lngLR_P = tblAdmin.Cells(tblAdmin.Rows.Count, 16).End(xlUp).Row
  lngLR_U = tblAdmin.Cells(tblAdmin.Rows.Count, 21).End(xlUp).Row

  If lngLR_P >= 9 + glngAddCtrls Then
    glngAddCtrls = glngAddCtrls + 1
    Me.Height = Me.Height + (30 * glngAddCtrls)
    lngUFHeight = 230
    Set objNewLB = Me.Controls.Add("Forms.label.1", True)
    With objNewLB
      .Name = "Label" & glngAddCtrls + 9
      .Left = 30
      .Height = 22
      .Width = 108
      .Top = lngUFHeight + (25 * glngAddCtrls)
      .Caption = tblAdmin.Range("U" & glngAddCtrls + 9).Value
    End With
    Set objNewCB = Me.Controls.Add("Forms.combobox.1", True)
    With objNewCB
      .Name = "Combobox" & glngAddCtrls
      .Left = 168
      .Height = 22
      .Width = 108
      .Style = 2
      .Top = lngUFHeight + (25 * glngAddCtrls)
      .RowSource = tblAdmin.Name & "!P2:P" & lngLR_P
    End With
    With cmdAdd
      .Left = 30
      .Top = lngUFHeight + 5 + (25 * (glngAddCtrls + 2))
    End With
    With cmdProc
      .Left = 168
      .Top = lngUFHeight + 5 + (25 * (glngAddCtrls + 2))
    End With
    With Label9
      .Left = 30
      .Top = lngUFHeight + (30 * (glngAddCtrls + 1))
      If glngAddCtrls > 0 Then
        .Caption = glngAddCtrls & " Fields Added"
      End If
    End With
  Else
    MsgBox "Please check the data in '" & gwkbImport.FullName & vbCrLf & _
            "as the number of Headers to import does not equal at least '" & _
            8 + glngAddCtrls, vbInformation, "Not enough data"
    Unload Me
  End If

end_here:
  On Error GoTo 0
  Exit Sub

err_here:
  Debug.Print "Actual procedure name: " & cstrProcName & vbCrLf & _
              "Error number: " & Err.Number & vbCrLf & _
              "Error description: " & Err.Description
  Err.Clear
  On Error GoTo 0
  Resume end_here

End Sub

Private Sub cmdProc_Click()
  Dim blnComplete       As Boolean
  Dim blnWBCheck        As Boolean
  Dim objCtrl           As Control
  Dim lngCounter        As Long
  Dim lngUnique         As Long
  Dim lngAll            As Long
  Dim lngDouble         As Long
  Dim varUnique()       As Variant
  Dim varAll()          As Variant
  Dim wb                As Workbook

  Const clngMaxDoubles  As Long = 2
  Const cstrProcName    As String = "cmdProc_Click"
 
  On Error GoTo err_here
 
  ReDim varUnique(1 To 1)
  ReDim varAll(1 To 1)
 
  If tblAdmin.Cells(tblAdmin.Rows.Count, 16).End(xlUp).Row >= 9 + glngAddCtrls Then
    For Each objCtrl In Me.Controls
      If TypeOf objCtrl Is MSForms.ComboBox Then
        With objCtrl
          blnComplete = Len(.Value) > 0
          If blnComplete Then
            lngAll = lngAll + 1
            ReDim Preserve varAll(1 To lngAll)
            varAll(lngAll) = .Value
            If IsError(Application.Match(.Value, varUnique, 0)) Then
              lngUnique = lngUnique + 1
              ReDim Preserve varUnique(1 To lngUnique)
              varUnique(lngUnique) = .Value
            Else
              lngDouble = lngDouble + 1
              If lngDouble = clngMaxDoubles Then
                Select Case MsgBox("Max of items to duplicate reached." & vbCrLf & _
                      "Ignore - Continue" & vbCrLf & _
                      "Retry - Change Item" & vbCrLf & _
                      "Abort - End Process", vbAbortRetryIgnore, "What to do?")
                  Case vbIgnore
                    Exit For
                  Case vbRetry
                    .SetFocus
                    GoTo end_here
                  Case vbAbort
                    GoTo end_here
                End Select
              End If
            End If
          Else
            MsgBox "Please fill blank field", 48, "Entry Required"
            .SetFocus
            GoTo end_here
          End If
        End With
      End If
      Err.Clear
      On Error GoTo 0
    Next objCtrl
   
    If blnComplete Then
      Err.Clear
      On Error GoTo 0
      With tblAdmin
        .Range("S2", .Range("S" & .Rows.Count).End(xlUp)).ClearContents
        .Range("S2").Resize(UBound(varAll), 1).Value = WorksheetFunction.Transpose(varAll)
      End With
      For Each wb In Workbooks
        If wb.Name = mstrNameWB Then
          blnWBCheck = True
          Exit For
        End If
      Next wb
      If blnWBCheck = False Then
        Set gwkbImport = Workbooks.Open(mstrFullNameWB)
        Set gwsNewheader = gwkbImport.Sheets(mstrNameWS)
      End If
      gblnCleanUp = False
      Unload Me
      Call DataImport
    End If
  Else
    MsgBox "Please check the data in '" & mstrFullNameWB & vbCrLf & _
            "as the number of Headers to import does not equal at least '" & _
            8 + glngAddCtrls, vbInformation, "Not enough data"
    Unload Me
  End If

end_here:
  Erase varUnique
  Erase varAll
  Err.Clear
  On Error GoTo 0
  Exit Sub

err_here:
  Debug.Print "Actual procedure name: " & cstrProcName & vbCrLf & _
              "Error number: " & Err.Number & vbCrLf & _
              "Error description: " & Err.Description
  Err.Clear
  On Error GoTo 0
  Resume end_here

End Sub

Private Sub UserForm_Terminate()

  Call CleanUp

End Sub

Module modDataImport:

VBA Code:
Sub DataImport()
  Dim lngImport       As Long
  Dim lngItems        As Long
  Dim strCol          As String
   
  Const cstrProcName  As String = "DataImport"
 
  On Error GoTo err_here
  Application.ScreenUpdating = False
  tblResult.UsedRange.ClearContents
  tblQuery.Range("A1:U1").Copy
  With tblResult.Range("A1:U1")
      .PasteSpecial Paste:=xlPasteValues, _
                    Operation:=xlNone, _
                    SkipBlanks:=False, _
                    Transpose:=False
      .PasteSpecial Paste:=xlPasteFormats, _
                    Operation:=xlNone, _
                    SkipBlanks:=False, _
                    Transpose:=False
  End With
 
  With tblAdmin
    For lngImport = 2 To .Cells(Rows.Count, 19).End(xlUp).Row
      strCol = .Range("T" & lngImport).Value
      lngItems = gwsNewheader.Range(strCol & Rows.Count).End(xlUp).Row
      gwsNewheader.Range(strCol & 1).Resize(lngItems, 1).Copy tblResult.Cells(1, lngImport - 1)
    Next lngImport
  End With
 
  gwkbImport.Close SaveChanges:=False
  Application.ScreenUpdating = True
 
  With tblAdmin
    .Range("P2", .Cells(.Rows.Count, "Q").End(xlUp)).ClearContents
    .Range("S2", .Cells(.Rows.Count, "S").End(xlUp)).ClearContents
    .Range("R1").ClearContents
  End With
  Application.Goto ThisWorkbook.Worksheets("Input").Range("A1"), Scroll:=True
  
end_here:
  Set gwsNewheader = Nothing
  Set gwkbImport = Nothing
  Err.Clear
  On Error GoTo 0
  Exit Sub

err_here:
  Debug.Print "Actual procedure name: " & cstrProcName & vbCrLf & _
              "Error number: " & Err.Number & vbCrLf & _
              "Error description: " & Err.Description
  Err.Clear
  On Error GoTo 0
  Resume end_here
 
End Sub

Module modStartUF:

VBA Code:
Public gwkbImport As Workbook
Public gwsNewheader As Worksheet
Public gblnCleanUp As Boolean
Public glngAddCtrls As Long
'

Sub Call_UF()

  UserForm1.Show 'vbModeless

End Sub

Sub CleanUp()
  If gblnCleanUp Then
    gwkbImport.Close False
    Set gwsNewheader = Nothing
    Set gwkbImport = Nothing
    gblnCleanUp = False
    With tblAdmin
      .Range("P2", .Cells(.Rows.Count, "Q").End(xlUp)).ClearContents
      .Range("S2", .Cells(.Rows.Count, "S").End(xlUp)).ClearContents
      .Range("R1").ClearContents
    End With
  End If
  Application.Goto ThisWorkbook.Worksheets("Input").Range("A1"), Scroll:=True
End Sub

ThisWorkbook/DieseArbeitsmappe:

VBA Code:
Private Sub Workbook_Open()
  Application.Goto tblInput.Range("G4"), False
End Sub

Link: MrE_1612814 1220041 Upload 221029.xlsm

Ciao,
Holger
Hi Holger,

Thanks for the revised code. It works as expected.
If you have time can you look into the below thread, please?
I need to replicate the solution provided in VBA or you can suggest a new solution if you know.

Thanks.
 
Upvote 0

Excel Facts

Copy formula down without changing references
If you have =SUM(F2:F49) in F50; type Alt+' in F51 to copy =SUM(F2:F49) to F51, leaving the formula in edit mode. Change SUM to COUNT.
Hi bmck29,

thanks for the feedback.

I took a look at the linked thread but I'm missing information which could be essential in trying to solve the challenge. You mention 11111, 22222, 33333 (5 digits) as well as 123456 (6 digits) but you do not indicate if you want an inputbox to get just one item to search for or if you have a list where those items can be found. Or will you just search for any combination of say more than 3 digits? And what about letters in place of numbers?

How do the numbers look like: 0172 12345678 (german handy number national call), 001-415-642-4321 (american handy number from outside US), 642-4321 (call in the same city), 0800 012 3456. Are those samples formatted in a custom way (displaying just numbers in the formula bar) or are the formatted as displayed? Is the formatting equal to all numbers?

Sorry but for me there are a lot of questions open before I could think of any solution to work on. I hope you will get an answer which will do the trick.

Ciao,
Holger
 
Upvote 0
Hi bmck29,

thanks for the feedback.

I took a look at the linked thread but I'm missing information which could be essential in trying to solve the challenge. You mention 11111, 22222, 33333 (5 digits) as well as 123456 (6 digits) but you do not indicate if you want an inputbox to get just one item to search for or if you have a list where those items can be found. Or will you just search for any combination of say more than 3 digits? And what about letters in place of numbers?

How do the numbers look like: 0172 12345678 (german handy number national call), 001-415-642-4321 (american handy number from outside US), 642-4321 (call in the same city), 0800 012 3456. Are those samples formatted in a custom way (displaying just numbers in the formula bar) or are the formatted as displayed? Is the formatting equal to all numbers?

Sorry but for me there are a lot of questions open before I could think of any solution to work on. I hope you will get an answer which will do the trick.

Ciao,
Holger
Hi Holger,
It's a Phone number column from the 8 Mandatory Fields. The numbers might be repeated/sequenced within a cell example (1111111111, 1234567890) repeated numbers could be any numbers.
I need to find the repeated numbers if more than 5 digits (excluding country code) and highlight them.
If text, NO need to do the finding process.
It's of various countries' data so no specific format.
With my code, I'm able to identify the repeated numbers without any country code and sequence numbers only if it is from the beginning. Ex 9841234567 is not identified.

Also, the below line of code doesn't verify the cell value to be numeric or text. Is there an alternative?
If IsNumeric(tblInput.Range("D2").Value) = True Then GoTo 12

Thanks
 
Upvote 0
Hi bcmk29,

good to hear that at least the run with the test data was okay.

A couple of questions and remarks came up to me, let me put them up. The Numbers are only for having an oriantation, they do not stand for importance.

1. In cmdAdd you wanted Listboxes to be added but there is no further code indicated that should be used by these new LBs. From what I understand I would rather use Labels and add the Caption to these from Sheet3 starting with U10. Altered code may look like

VBA Code:
      Set objNewLB = Me.Controls.Add("Forms.label.1", True)
      With objNewLB
        .Name = "Label" & glngAddCtrls + 9
        .Left = 30
        .Height = 22
        .Width = 108
        .Top = lngUFHeight + (25 * glngAddCtrls)
        .Caption = tblAdmin.Range("U" & glngAddCtrls + 9).Value
      End With

As you can spot from the code I changed the static variable to a public one as I would use that in cmdProc as well.


2. Although this is a minor I would check the number of the imported headers to equal or exceed 8 for both cmdAdd and cmdProc, otherwise you will run into trouble when trying to import the data. Start of code for cmdAdd may look like

VBA Code:
  lngLR_P = tblAdmin.Cells(tblAdmin.Rows.Count, 16).End(xlUp).Row
  lngLR_U = tblAdmin.Cells(tblAdmin.Rows.Count, 21).End(xlUp).Row

  If lngLR_P >= 9 + glngAddCtrls Then
    If cblnHaHoBe Then

while at the end this code would be entered

VBA Code:
    End If
  Else
    MsgBox "Please check the data in '" & gwkbImport.FullName & vbCrLf & _
            "as the number of Headers to import does not equal at least '" & _
            8 + glngAddCtrls, vbInformation, "Not enough data"
    Unload Me
  End If

3. Right now the comboboxes are left as default. This means that any item from the list may be chosen but as well you may insert any text you want. I would recommend to limit the use to just choose items form the list. Code should be altered in UserForm_Activate

VBA Code:
  For Each objCtrl In Me.Controls
    If TypeOf objCtrl Is MSForms.ComboBox Then
      objCtrl.List = rng2List.Value
      objCtrl.Style = 2
    End If
  Next objCtrl

and cmdAdd_Click

VBA Code:
      With objNewCB
        .Name = "Combobox" & glngAddCtrls
        .Left = 168
        .Height = 22
        .Width = 108
        .Style = 2
        .Top = lngUFHeight + (25 * glngAddCtrls)
        .RowSource = tblAdmin.Name & "!P2:P" & lngLR_P
      End With

The long 2 used here stands for frmStyleDropDownList, the default is 0 or frmStyleDropDownCombo.

4. Up to now you may close the UserForm via X on the right upper top. But as you want to unload the UserForm before calling DataImport any code for cleaning up would be in the wrong place directly behind the userForm (my point of view, I may be totally wrong here). So I added a new public variable gblnCleanUp which is switched to True at the begin of UserForm_Initialize. I added a new procedure to the UserForm

VBA Code:
Private Sub UserForm_Terminate()

  Call CleanUp

End Sub

and one in modStartUF

VBA Code:
Sub CleanUp()
  If gblnCleanUp Then
    gwkbImport.Close False
    Set gwsNewHeader = Nothing
    Set gwkbImport = Nothing
    gblnCleanUp = False
    With tblAdmin
      .Range("P2", .Cells(.Rows.Count, "P").End(xlUp)).ClearContents
      .Range("S2", .Cells(.Rows.Count, "S").End(xlUp)).ClearContents
      .Range("R1").ClearContents
    End With
  End If
  Application.GoTo ThisWorkbook.Worksheets("Input").Range("A1"), Scroll:=True
End Sub

And to top all this the code at the end of cmdProc needs to be changed as of now the public variables would be cut

VBA Code:
    If blnComplete Then
      Err.Clear
      On Error GoTo 0
      With tblAdmin
        .Range("S2", .Range("S" & .Rows.Count).End(xlUp)).ClearContents
        For lngCounter = 1 To objColNoDupes.Count
          .Range("S" & lngCounter + 1).Value = objColNoDupes(lngCounter)
        Next lngCounter
      End With
      gblnCleanUp = False
      Unload Me
      Call DataImport
    End If

5. You apply formulas in Sheet3 to get the Information about the columns. This may be done by VBA using WorksheetFunction.VLookUp.

6. The check for the information about the Column Letters isn't foolproof as you may insert a cell address like A32 which would be accepted.

You may download the updated workbook MrE_1612814 1220041 Upload 221026.xlsm

Ciao,
Hiolger
Hi Holger,

By chance did you limit the No of headers a user can add in the userform. I ended up in a scenario where I need to add 5 headers, and when I do that the Proceed button doesn't work. I tried with 4 new headers and the code works without any issue. Please advice.
 
Upvote 0
Hi bcmk29,

in cmdAdd_Click at the beginning the code checks the last row of entries on "Sheet3" in Column P and compares that to 8 headers and the number of the newly added headers. If you want to add additional headers you should modify the codeline

VBA Code:
  If lngLR_P >= 9 + glngAddCtrls Then

to

VBA Code:
  If lngLR_P > 8 + glngAddCtrls Then

which will allow an additional header to double up.

While testing for this I realized that the UserForm gets "out of form" so I slightly altered the code including enabling the button when the maximum is reached (so avoiding any errors):

VBA Code:
Private Sub cmdAdd_Click()
  Dim objNewLB        As Object
  Dim objNewCB        As Object
  Dim lngUFHeight     As Long
  Dim lngLR_P         As Long
  Dim lngLR_U         As Long
  
  Const cstrProcName  As String = "cmdAdd_Click"
  
  On Error GoTo err_here
  
  lngLR_P = tblAdmin.Cells(tblAdmin.Rows.Count, 16).End(xlUp).Row
  lngLR_U = tblAdmin.Cells(tblAdmin.Rows.Count, 21).End(xlUp).Row

  If lngLR_P > 8 + glngAddCtrls Then
    glngAddCtrls = glngAddCtrls + 1
    Me.Height = Me.Height + 25
    lngUFHeight = 230
    Set objNewLB = Me.Controls.Add("Forms.label.1", True)
    With objNewLB
      .Name = "Label" & glngAddCtrls + 9
      .Left = 30
      .Height = 22
      .Width = 108
      .Top = lngUFHeight + (25 * glngAddCtrls)
      .Caption = tblAdmin.Range("U" & glngAddCtrls + 9).Value
    End With
    Set objNewCB = Me.Controls.Add("Forms.combobox.1", True)
    With objNewCB
      .Name = "Combobox" & glngAddCtrls
      .Left = 168
      .Height = 22
      .Width = 108
      .Style = 2
      .Top = lngUFHeight + (25 * glngAddCtrls)
      .RowSource = tblAdmin.Name & "!P2:P" & lngLR_P
    End With
    With cmdAdd
      .Left = 30
      .Top = lngUFHeight + 5 + (25 * (glngAddCtrls + 2))
    End With
    With cmdProc
      .Left = 168
      .Top = lngUFHeight + 5 + (25 * (glngAddCtrls + 2))
    End With
    With Label9
      .Left = 30
      .Top = lngUFHeight + (25 * (glngAddCtrls + 1))
      If glngAddCtrls > 0 Then
        .Caption = glngAddCtrls & " Fields Added"
      End If
    End With
    If lngLR_P = 8 + glngAddCtrls Then cmdAdd.Enabled = False
  Else
    MsgBox "Please check the data in '" & gwkbImport.FullName & vbCrLf & _
            "as the number of Headers to import does not equal at least " & _
            lngLR_P & "' entires (one to double included)", vbInformation, "Not enough data"
    Unload Me
  End If

end_here:
  On Error GoTo 0
  Exit Sub

err_here:
  Debug.Print "Actual procedure name: " & cstrProcName & vbCrLf & _
              "Error number: " & Err.Number & vbCrLf & _
              "Error description: " & Err.Description
  Err.Clear
  On Error GoTo 0
  Resume end_here

End Sub

Ciao,
Holger
 
Upvote 0
T
Hi bcmk29,

in cmdAdd_Click at the beginning the code checks the last row of entries on "Sheet3" in Column P and compares that to 8 headers and the number of the newly added headers. If you want to add additional headers you should modify the codeline

VBA Code:
  If lngLR_P >= 9 + glngAddCtrls Then

to

VBA Code:
  If lngLR_P > 8 + glngAddCtrls Then

which will allow an additional header to double up.

While testing for this I realized that the UserForm gets "out of form" so I slightly altered the code including enabling the button when the maximum is reached (so avoiding any errors):

VBA Code:
Private Sub cmdAdd_Click()
  Dim objNewLB        As Object
  Dim objNewCB        As Object
  Dim lngUFHeight     As Long
  Dim lngLR_P         As Long
  Dim lngLR_U         As Long
 
  Const cstrProcName  As String = "cmdAdd_Click"
 
  On Error GoTo err_here
 
  lngLR_P = tblAdmin.Cells(tblAdmin.Rows.Count, 16).End(xlUp).Row
  lngLR_U = tblAdmin.Cells(tblAdmin.Rows.Count, 21).End(xlUp).Row

  If lngLR_P > 8 + glngAddCtrls Then
    glngAddCtrls = glngAddCtrls + 1
    Me.Height = Me.Height + 25
    lngUFHeight = 230
    Set objNewLB = Me.Controls.Add("Forms.label.1", True)
    With objNewLB
      .Name = "Label" & glngAddCtrls + 9
      .Left = 30
      .Height = 22
      .Width = 108
      .Top = lngUFHeight + (25 * glngAddCtrls)
      .Caption = tblAdmin.Range("U" & glngAddCtrls + 9).Value
    End With
    Set objNewCB = Me.Controls.Add("Forms.combobox.1", True)
    With objNewCB
      .Name = "Combobox" & glngAddCtrls
      .Left = 168
      .Height = 22
      .Width = 108
      .Style = 2
      .Top = lngUFHeight + (25 * glngAddCtrls)
      .RowSource = tblAdmin.Name & "!P2:P" & lngLR_P
    End With
    With cmdAdd
      .Left = 30
      .Top = lngUFHeight + 5 + (25 * (glngAddCtrls + 2))
    End With
    With cmdProc
      .Left = 168
      .Top = lngUFHeight + 5 + (25 * (glngAddCtrls + 2))
    End With
    With Label9
      .Left = 30
      .Top = lngUFHeight + (25 * (glngAddCtrls + 1))
      If glngAddCtrls > 0 Then
        .Caption = glngAddCtrls & " Fields Added"
      End If
    End With
    If lngLR_P = 8 + glngAddCtrls Then cmdAdd.Enabled = False
  Else
    MsgBox "Please check the data in '" & gwkbImport.FullName & vbCrLf & _
            "as the number of Headers to import does not equal at least " & _
            lngLR_P & "' entires (one to double included)", vbInformation, "Not enough data"
    Unload Me
  End If

end_here:
  On Error GoTo 0
  Exit Sub

err_here:
  Debug.Print "Actual procedure name: " & cstrProcName & vbCrLf & _
              "Error number: " & Err.Number & vbCrLf & _
              "Error description: " & Err.Description
  Err.Clear
  On Error GoTo 0
  Resume end_here

End Sub

Ciao,
Holger
Thanks,

VBA Code:
  If tblAdmin.Cells(tblAdmin.Rows.Count, 16).End(xlUp).Row >= 8 + glngAddCtrls Then

This is where the code Exits I changed 9 to 8 and it works fine now. Thanks for the guidance.
 
Upvote 0
Hi Holger,

The below code checks for blanks in the 2nd & 4th cells of a column. I ended in a scenario where the data was present beyond the 4th cell and the code excluded importing the column header.

VBA Code:
        If WorksheetFunction.CountBlank(.Range(.Cells(2, lngCounter), .Cells(4, lngCounter))) = 0 Then

Need help checking blanks for the entire column except header. If true don't import the header or import the header.

Thanks.
 
Upvote 0
Hi bcmk29,

change UserForm_Initialize to

VBA Code:
Private Sub UserForm_Initialize()
  Dim lngIndexWS      As Long       'index of worksheet in new workbook if more than one worksheet
  Dim lngWS           As Long       'counter for index of worksheets in opened workbook
  Dim varFile         As Variant    'variable to hold path and filename for workbook to open
  Dim varArr()        As Variant    'values for the header values to be copied
  Dim strWS           As String     'Holding the names of worksheets of new workbook
  Dim ws              As Worksheet  'for looping worksheets in new workbook
  Dim wb              As Workbook   'for looping through all open workbooks
  Dim blnRunOnce      As Boolean    'boolean for getting information about worksheets,
  Dim blnUnload       As Boolean    'boolean whether to unload the UF
  Dim lngColMax       As Long
  Dim lngCounter      As Long
  Dim lngArr          As Long
  Dim strAddress      As String
  
  Const cstrProcName  As String = "UserForm1_Initialize"
  Const cblnBcmk      As Boolean = False
  
  On Error GoTo err_here
  blnUnload = False
  gblnCleanUp = True
  
  If tblInput.Cells(Rows.Count, 1).End(xlUp).Row <> 1 Then GoTo end_here
  
  If gwkbImport Is Nothing Then
    varFile = Application.GetOpenFilename("(*.xlsx),", MultiSelect:=False)
    If varFile = False Then
      MsgBox "No file selected to import.", 48
      blnUnload = True
      GoTo end_here
    End If
    Set gwkbImport = Workbooks.Open(Filename:=varFile)
  Else
    For Each wb In Workbooks
      If wb.Name = gwkbImport.Name Then Exit For
    Next wb
    Set gwkbImport = Workbooks.Open(Filename:=varFile)
  End If
  mstrFullNameWB = gwkbImport.FullName
  mstrNameWB = gwkbImport.Name
  
  If cblnBcmk Then MsgBox gwkbImport.FullName
  If gwsNewheader Is Nothing Then
    If gwkbImport.Worksheets.Count > 1 Then
      blnRunOnce = False
reIB:
      If blnRunOnce = False Then
        For Each ws In gwkbImport.Worksheets
          lngWS = lngWS + 1
          strWS = strWS & lngWS & " : " & ws.Name & vbCrLf
        Next ws
        blnRunOnce = True
      End If
      lngIndexWS = Application.InputBox("Enter worksheet number" & vbCrLf & Left(strWS, Len(strWS) - 1), "Worksheet selection", , , , , , 1)
      If lngIndexWS > gwkbImport.Worksheets.Count Then
        MsgBox "Invalid Worksheet Input, Try Again.", 48, "Entry Required"
        GoTo reIB
      ElseIf lngIndexWS = 0 Then
        MsgBox "Procedure cancelled", vbInformation, "Stopping here"
        gwkbImport.Close False
        Set gwkbImport = Nothing
        blnUnload = True
        GoTo end_here
      Else
        Set gwsNewheader = gwkbImport.Worksheets(lngIndexWS)
      End If
    Else
      Set gwsNewheader = gwkbImport.Worksheets(1)
    End If
  End If
  mstrNameWS = gwsNewheader.Name

  Err.Clear
  On Error GoTo 0
  If blnUnload = False Then
    tblAdmin.Range("P2:P" & tblAdmin.Rows.Count).ClearContents
    With gwsNewheader
      lngColMax = .Cells(1, Columns.Count).End(xlToLeft).Column
'/// start change 221104, HaHoBe
'/// due to occasional missing entries
'///
      '/// use the number of columns to ReDim the array to hold data
'      lngArr = lngColMax - WorksheetFunction.CountBlank(.Range(.Cells(2, 1), .Cells(2, lngColMax)))
      ReDim varArr(1 To lngColMax, 1 To 2)
'/// end  change 221104, HaHoBe
      lngArr = 0
      For lngCounter = 1 To lngColMax
'/// start change 221104, HaHoBe
'/// due to occasional missing entries
'///
        '/// check if any data is present between row 2 and the number of used rows in the sheet
        If WorksheetFunction.CountA(.Range(.Cells(2, lngCounter), .Cells(.Range("A1").CurrentRegion.Rows.Count, lngCounter))) > 0 Then
'/// end  change 221104, HaHoBe
          lngArr = lngArr + 1
          With .Cells(1, lngCounter)
            varArr(lngArr, 1) = .Value
            strAddress = Left(.Address(0, 0), Len(.Address(0, 0)) - 1)
            varArr(lngArr, 2) = strAddress '& ":" & strAddress
          End With
        End If
      Next lngCounter
    End With
    tblAdmin.Range("P2").Resize(UBound(varArr, 1), 2).Value = varArr
    Erase varArr
    Application.Goto tblAdmin.Range("P1"), True
  End If

end_here:
  Err.Clear
  On Error GoTo 0
  If blnUnload Then End
  Exit Sub

err_here:
  Debug.Print "Actual procedure name: " & cstrProcName & vbCrLf & _
              "Error number: " & Err.Number & vbCrLf & _
              "Error description: " & Err.Description
  Err.Clear
  On Error GoTo 0
  Resume end_here

End Sub

The array will hold the number of columns no matter if they have data below or not. It's not the way I would normally handle this but by now it seems to be the easiest change of code to allow what you are asking for instead of rewriting part of the code.

Ciao,
Holger
 
Upvote 0
Hi bcmk29,

change UserForm_Initialize to

VBA Code:
Private Sub UserForm_Initialize()
  Dim lngIndexWS      As Long       'index of worksheet in new workbook if more than one worksheet
  Dim lngWS           As Long       'counter for index of worksheets in opened workbook
  Dim varFile         As Variant    'variable to hold path and filename for workbook to open
  Dim varArr()        As Variant    'values for the header values to be copied
  Dim strWS           As String     'Holding the names of worksheets of new workbook
  Dim ws              As Worksheet  'for looping worksheets in new workbook
  Dim wb              As Workbook   'for looping through all open workbooks
  Dim blnRunOnce      As Boolean    'boolean for getting information about worksheets,
  Dim blnUnload       As Boolean    'boolean whether to unload the UF
  Dim lngColMax       As Long
  Dim lngCounter      As Long
  Dim lngArr          As Long
  Dim strAddress      As String
 
  Const cstrProcName  As String = "UserForm1_Initialize"
  Const cblnBcmk      As Boolean = False
 
  On Error GoTo err_here
  blnUnload = False
  gblnCleanUp = True
 
  If tblInput.Cells(Rows.Count, 1).End(xlUp).Row <> 1 Then GoTo end_here
 
  If gwkbImport Is Nothing Then
    varFile = Application.GetOpenFilename("(*.xlsx),", MultiSelect:=False)
    If varFile = False Then
      MsgBox "No file selected to import.", 48
      blnUnload = True
      GoTo end_here
    End If
    Set gwkbImport = Workbooks.Open(Filename:=varFile)
  Else
    For Each wb In Workbooks
      If wb.Name = gwkbImport.Name Then Exit For
    Next wb
    Set gwkbImport = Workbooks.Open(Filename:=varFile)
  End If
  mstrFullNameWB = gwkbImport.FullName
  mstrNameWB = gwkbImport.Name
 
  If cblnBcmk Then MsgBox gwkbImport.FullName
  If gwsNewheader Is Nothing Then
    If gwkbImport.Worksheets.Count > 1 Then
      blnRunOnce = False
reIB:
      If blnRunOnce = False Then
        For Each ws In gwkbImport.Worksheets
          lngWS = lngWS + 1
          strWS = strWS & lngWS & " : " & ws.Name & vbCrLf
        Next ws
        blnRunOnce = True
      End If
      lngIndexWS = Application.InputBox("Enter worksheet number" & vbCrLf & Left(strWS, Len(strWS) - 1), "Worksheet selection", , , , , , 1)
      If lngIndexWS > gwkbImport.Worksheets.Count Then
        MsgBox "Invalid Worksheet Input, Try Again.", 48, "Entry Required"
        GoTo reIB
      ElseIf lngIndexWS = 0 Then
        MsgBox "Procedure cancelled", vbInformation, "Stopping here"
        gwkbImport.Close False
        Set gwkbImport = Nothing
        blnUnload = True
        GoTo end_here
      Else
        Set gwsNewheader = gwkbImport.Worksheets(lngIndexWS)
      End If
    Else
      Set gwsNewheader = gwkbImport.Worksheets(1)
    End If
  End If
  mstrNameWS = gwsNewheader.Name

  Err.Clear
  On Error GoTo 0
  If blnUnload = False Then
    tblAdmin.Range("P2:P" & tblAdmin.Rows.Count).ClearContents
    With gwsNewheader
      lngColMax = .Cells(1, Columns.Count).End(xlToLeft).Column
'/// start change 221104, HaHoBe
'/// due to occasional missing entries
'///
      '/// use the number of columns to ReDim the array to hold data
'      lngArr = lngColMax - WorksheetFunction.CountBlank(.Range(.Cells(2, 1), .Cells(2, lngColMax)))
      ReDim varArr(1 To lngColMax, 1 To 2)
'/// end  change 221104, HaHoBe
      lngArr = 0
      For lngCounter = 1 To lngColMax
'/// start change 221104, HaHoBe
'/// due to occasional missing entries
'///
        '/// check if any data is present between row 2 and the number of used rows in the sheet
        If WorksheetFunction.CountA(.Range(.Cells(2, lngCounter), .Cells(.Range("A1").CurrentRegion.Rows.Count, lngCounter))) > 0 Then
'/// end  change 221104, HaHoBe
          lngArr = lngArr + 1
          With .Cells(1, lngCounter)
            varArr(lngArr, 1) = .Value
            strAddress = Left(.Address(0, 0), Len(.Address(0, 0)) - 1)
            varArr(lngArr, 2) = strAddress '& ":" & strAddress
          End With
        End If
      Next lngCounter
    End With
    tblAdmin.Range("P2").Resize(UBound(varArr, 1), 2).Value = varArr
    Erase varArr
    Application.Goto tblAdmin.Range("P1"), True
  End If

end_here:
  Err.Clear
  On Error GoTo 0
  If blnUnload Then End
  Exit Sub

err_here:
  Debug.Print "Actual procedure name: " & cstrProcName & vbCrLf & _
              "Error number: " & Err.Number & vbCrLf & _
              "Error description: " & Err.Description
  Err.Clear
  On Error GoTo 0
  Resume end_here

End Sub

The array will hold the number of columns no matter if they have data below or not. It's not the way I would normally handle this but by now it seems to be the easiest change of code to allow what you are asking for instead of rewriting part of the code.

Ciao,
Holger
Thanks, works as expected now.
 
Upvote 0

Forum statistics

Threads
1,214,944
Messages
6,122,387
Members
449,080
Latest member
Armadillos

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top