object required within collection vba - vba

seems that I am a bit rusty when it comes to vba programming. I have created a licence type (class/object) and wishing to add that to a collection type. I am trying to iterate over the collection but keep getting object required error 424. Code snippet below for advise. thanks in advance
Private Sub btnGenerate_Click()
Dim lic As licence
For Each lic In licenceCollection
Debug.Print lic.getClause
Next lic
End Sub
error produced on for each lic in licenceCollection
Private Sub cboHeading_Change()
Dim heading As String
Dim str As String
'Dim lic As Licence
Dim rngValue As Range
Dim ws As Worksheet
Dim last_row As Long
Dim arr()
Dim i As Long
'Dim lic As licence
heading = cboHeading.Value
Set licenceCollection = New collection
Select Case heading
Case "Future Sampling"
'str = "lorem ipsum"
'Utility.createCheckBoxes (str)
'grab data from Future Sampling ws
Set ws = Worksheets("Future_Sampling")
ws.Activate
last_row = Range("A2").End(xlDown).Row
Debug.Print last_row
ReDim arr(last_row - 2)
'add array to object type
For i = 0 To last_row - 2
arr(i) = Range("A" & i + 2)
'Debug.Print arr(i)
Next
Set licence = New licence
licence.setClause = arr
'Debug.Print lic.getDescription
'add licence to collection for later retrieval
licenceCollection.Add (arr)
Case Else
Debug.Print ("no heading")
End Select
'Set lic = Nothing
End Sub
Private Sub UserForm_Initialize()
Dim rngValue As Range
Dim ws As Worksheet
Set ws = Worksheets("Headings")
For Each rngValue In ws.Range("A2:A10")
Me.cboHeading.AddItem rngValue.Value
Next rngValue
'licenceForm.cboHeading.SetFocus
'create vertical scrollbar
With Me.resultFrame
.ScrollBars = fmScrollBarsVertical
End With
End Sub

Thanks guys, that fixed my issue.
Private Sub btnGenerate_Click()
Dim i As Long
Dim lic As licence
Dim temp As Variant
For Each lic In licenceCollection
temp = lic.getClause
Next lic
For i = LBound(temp) To UBound(temp) Step 1
Debug.Print temp(i)
Next
End Sub
Private Sub cboHeading_Change()
Dim heading As String
Dim str As String
'Dim lic As Licence
Dim rngValue As Range
Dim ws As Worksheet
Dim last_row As Long
Dim arr()
Dim i As Long
Dim lic As licence
heading = cboHeading.Value
Set licenceCollection = New collection
Select Case heading
Case "Future Sampling"
'str = "lorem ipsum "
'Utility.createCheckBoxes (str)
'grab data from Future Sampling ws
Set ws = Worksheets("Future_Sampling")
ws.Activate
last_row = Range("A2").End(xlDown).Row
Debug.Print last_row
ReDim arr(last_row - 2)
'add array to object type
For i = 0 To last_row - 2
arr(i) = Range("A" & i + 2)
'Debug.Print arr(i)
Next
Set lic = New licence
lic.setClause = arr
'Debug.Print lic.getDescription
'add licence to collection for later retrieval
licenceCollection.Add lic
Case Else
Debug.Print ("no heading")
End Select
'Set lic = Nothing
End Sub

Related

Copy range in Word avoiding clipboard

I have the code below to copy an array of tables in Word to Excel. The volume of data being copied gives memory problems, so I would like to avoid the clipboard - i.e. avoid using Range.Copy
Word does not support Range.Value and I have not been able to get Range(x) = Range(y) to work.
Any suggestions for a way to avoid the clipboard? Word formatting can be junked.
Sub ImportWordTableArray()
Dim WordApp As Object
Dim WordDoc As Object
Dim arrFileList As Variant, FileName As Variant
Dim tableNo As Integer 'table number in Word
Dim tableStart As Integer
Dim tableTot As Integer
Dim Target As Range
On Error Resume Next
arrFileList = Application.GetOpenFilename("Word files (*.doc; *.docx),*.doc;*.docx", 2, _
"Browse for file containing table to be imported", , True)
If Not IsArray(arrFileList) Then Exit Sub
Set WordApp = CreateObject("Word.Application")
WordApp.Visible = False
Worksheets("Test").Range("A:AZ").ClearContents
Set Target = Worksheets("Test").Range("A1")
For Each FileName In arrFileList
Set WordDoc = WordApp.Documents.Open(FileName, ReadOnly:=True)
With WordDoc
'For array
Dim tables() As Variant
Dim tableCounter As Long
tableNo = WordDoc.tables.Count
tableTot = WordDoc.tables.Count
If tableNo = 0 Then
MsgBox WordDoc.Name & "Contains no tables", vbExclamation, "Import Word Table"
End If
tables = Array(1, 3, 5) '<- define array manually here if not using InputBox
For tableCounter = LBound(tables) To UBound(tables)
With .tables(tables(tableCounter))
.Range.Copy
Target.Activate
'Target.Parent.PasteSpecial Format:="Text", Link:=False, DisplayAsIcon:=False '<- memory problems!
'Or
ActiveSheet.Paste '<- pastes with formatting
Set Target = Target.Offset(.Rows.Count + 2, 0)
End With
Next tableCounter
.Close False
End With
Next FileName
WordApp.Quit
Set WordDoc = Nothing
Set WordApp = Nothing
End Sub
You may need to tweak the code below to get it to do exactly what you want (Excel is not something I use often) as the calculation of ranges is a bit wonky, but it will transfer text from word to excel without cutting and pasting
Option Explicit
' This code is based on it being in an Excel VBA Module with the reference
' to the Microsoft Word Object XX.X Object Library (Tools.References)
' enabled so that we get intellisense for Word objects
Public Enum ImportError
NoTablesInDocument
End Enum
Sub ImportWordTableArray()
Dim myFileList As Variant
If Not TryGetFileList(myFileList) Then Exit Sub
Dim myWdApp As Word.Application
Set myWdApp = New Word.Application
myWdApp.Visible = True
If Application.ReferenceStyle = xlA1 Then Application.ReferenceStyle = xlR1C1
ThisWorkbook.Worksheets("Test").Range("A:AZ").ClearContents
Dim myFileName As Variant
For Each myFileName In myFileList
Dim myDoc As Word.Document
If TryGetWordDoc(myFileName, myWdApp, myDoc) Then
CopyDocTablesToExcel myDoc, ThisWorkbook.Worksheets("Test")
End If
Next
If Application.ReferenceStyle = xlR1C1 Then Application.ReferenceStyle = xlA1
End Sub
Public Sub CopyDocTablesToExcel(ByVal ipDoc As Word.Document, ByVal ipWs As Excel.Worksheet)
If ipDoc.Tables.Count = 0 Then
Report ipDoc.Name, ImportError.NoTablesInDocument
Exit Sub
End If
Dim myTable As Variant
Dim Target As Excel.Range
For Each myTable In ipDoc.Tables
' This code assumes that the Word table is 'uniform'
Dim myCols As Long
myCols = myTable.Range.Tables.Item(1).Range.Columns.Count
Dim myRows As Long
myRows = myTable.Range.Tables.Item(1).Range.Rows.Count
Dim myTLCell As Excel.Range
Dim myBRCell As Excel.Range
If Target Is Nothing Then
Set myTLCell = ipWs.Cells(1, 1)
Set myBRCell = ipWs.Cells(myCols, myRows)
Else
Set myTLCell = ipWs.Cells(1, Target.Cells.SpecialCells(xlCellTypeLastCell).Row + 2)
Set myBRCell = ipWs.Cells(myCols, Target.Cells.SpecialCells(xlCellTypeLastCell).Row + 2 + myRows)
End If
Set Target = ipWs.Range(myTLCell, myBRCell)
Target = GetTableArray(myTable)
Next
End Sub
Public Function GetTableArray(ByVal ipTable As Word.Table) As Variant
Dim myArray As Variant
Dim myRow As Long
Dim myCol As Long
ReDim myArray(1 To ipTable.Range.Tables.Item(1).Range.Rows.Count, 1 To ipTable.Range.Tables.Item(1).Range.Columns.Count)
For myRow = 1 To UBound(myArray, 1) - 1
For myCol = 1 To UBound(myArray, 2) - 1
Dim myText As String
myText = ipTable.Cell(myRow, myCol).Range.Text
myArray(myRow, myCol) = VBA.Left$(myText, Len(myText) - 2)
Next
Next
GetTableArray = myArray
End Function
Public Function TryGetFileList(ByRef opFileList As Variant) As Boolean
On Error Resume Next
opFileList = _
Application.GetOpenFilename _
( _
"Word files (*.doc; *.docx),*.doc;*.docx", _
2, _
"Browse for file containing table to be imported", _
, _
True _
)
TryGetFileList = (Err.Number = 0) And IsArray(opFileList)
On Error GoTo 0
End Function
Public Function TryGetWordDoc _
( _
ByVal ipName As String, _
ByRef ipWdApp As Word.Application, _
ByRef opDoc As Word.Document _
) As Boolean
On Error Resume Next
Set opDoc = ipWdApp.Documents.Open(ipName, ReadOnly:=True)
TryGetWordDoc = (Err.Number = 0) And (Not opDoc Is Nothing)
On Error GoTo 0
End Function
Public Function Report(ByVal ipString As String, ByVal ipError As ImportError)
Select Case ipError
Case NoTablesInDocument
MsgBox ipString & " Contains no tables", vbExclamation, "Import Word Table"
Case Else
End Select
End Function
For tableCounter ... Next code modified below to extract data directly rather than using copy and paste.
Sub ImportWordTablesArray()
Dim WordApp As Object
Dim WordDoc As Object
Dim arrFileList As Variant, Filename As Variant
Dim tableNo As Integer 'table number in Word
Dim iRow As Long 'row index in Excel
Dim iCol As Integer 'column index in Excel
Dim resultRow As Long
Dim tables() As Variant
Dim tableCounter As Long
On Error Resume Next
arrFileList = Application.GetOpenFilename("Word files (*.doc; *.docx),*.doc;*.docx", 2, _
"Browse for file containing table to be imported", , True)
If Not IsArray(arrFileList) Then Exit Sub '<-user cancelled import file browser
Set WordApp = CreateObject("Word.Application")
WordApp.Visible = False
Worksheets("Test").Range("A:E").Clear '<-ClearContents to clear only text
For Each Filename In arrFileList
Set WordDoc = WordApp.Documents.Open(Filename, ReadOnly:=True)
With WordDoc
If WordDoc.ProtectionType <> wdNoProtection Then
WordDoc.Unprotect Password:=SREPedit
End If
tableNo = WordDoc.tables.Count
If tableNo = 0 Then
MsgBox WordDoc.Name & "Contains no tables", vbExclamation, "Import Word Table"
End If
tables = Array(1, 2, 8) '<- Select tables for data extraction
For tableCounter = LBound(tables) To UBound(tables)
With .tables(tables(tableCounter))
For iRow = 1 To .Rows.Count
For iCol = 1 To .Columns.Count
Cells(resultRow, iCol) = WorksheetFunction.Clean(.Cell(iRow, iCol).Range.Text)
Next iCol
resultRow = resultRow + 1
Next iRow
End With
resultRow = resultRow + 1
Next tableCounter
.Close False
End With
Next Filename
WordApp.Quit
Set WordDoc = Nothing
Set WordApp = Nothing
End Sub

How to sum a range of values from multiple worksheets

I want to sum the same range of values (say B3:B292) in 120 worksheets such that: ΣB3, ΣB4, ΣB5 ...... ΣB292.
I am not getting an error for the below VBA code, but it's also not returning any values.
Sub FAggreg1PNFAWO()
Dim Aggreg1PNFAWO As Workbook
Dim WS_Count As Integer
Dim filePath As String
Dim i As Integer
Dim TotalNp As Variant
filePath = "Directory"
Set Aggreg1PNFAWO = Workbooks.Open(filePath, ReadOnly:=True)
WS_Count = Aggreg1PNFAWO.Worksheets.Count
For i = 1 To WS_Count
'Sheets(i).range("B3:B292") <> "" And
If IsNumeric(Sheets(i).range("B3:B292")) Then
TotalNp = TotalNp + Sheets(i).range("B3:B292")
End If
Next
ActiveWorkbook.Close
ThisWorkbook.Activate
ActiveSheet.range("T4:T293").Value = TotalNp
End Sub
In that case try this:
Sub FAggreg1PNFAWO()
Dim Aggreg1PNFAWO As Workbook, myWB As Workbook
Dim WS_Count As Integer, i As Integer
Dim filePath As String
Dim TotalNp As Variant
Set myWB = ActiveWorkbook
filePath = "Directory"
Set Aggreg1PNFAWO = Workbooks.Open(filePath, ReadOnly:=True)
WS_Count = Aggreg1PNFAWO.Worksheets.Count
For X = 3 To 292
For i = 1 To WS_Count
If IsNumeric(Sheets(i).Range("B" & X)) Then
TotalNp = TotalNp + Sheets(i).Range("B" & X).Value
End If
Next
myWB.Activate
myWB.ActiveSheet.Range("T" & i + 1).Value = TotalNp
TotalNp = 0
Aggreg1PNFAWO.Activate
Next X
End Sub
Here you can use SUM function to do this. In the below answer am assuming B293 cell as empty and using it for summation. If you have some data in that cell then pick some other empty cell then try this.
Sub Sum()
Dim Project1P As Workbook
Dim WS_Count As Integer
Dim i As Integer
Dim V As Variant
Set Project1P = Workbooks.Open("C:\Users\Nandan\Desktop\SO\SO1.xlsx")
WS_Count = Project1P.Worksheets.Count
sumrange (WS_Count)
End Sub
Function sumrange(TotalSheets As Integer)
Dim reserves As Variant
For i = 1 To TotalSheets
Sheets(i).range("B" & 293).Formula = "=SUM(B3:B292)"
Next
For i = 1 To TotalSheets
reserves = reserves + Sheets(i).range("B" & 293)
Next
For i = 1 To TotalSheets
Sheets(i).range("B" & 293).Clear
Next
MsgBox "Total of all sheets :" & reserves
End Function

Unique list from a matrix to a single column

I needed to collect a unique list of text from a matrix, ("J19:BU500" in my case which contains duplicates) and paste it in a column (column DZ in my case) in the same sheet.
I need to loop this for multiple sheets in the same workbook. I'm new to VBA and got this code from internet and customized a bit to my requirement. But I have two problems with the code:
When the matrix is empty in say sheet 5, the code runs fine upto sheet 4 and throws a runtime error at sheet5 and stops without looping further to next sheets.
Also, I actually wanted the unique list to start at Cell "DZ10". If I do that, the number of unique list reduces by 10. For say there are 25 uniques, only 15 gets pasted starting from cell "DZ10" whereas all 25 gets pasted from cell "DZ1".
Code:
Public Function CollectUniques(rng As Range) As Collection
Dim varArray As Variant, var As Variant
Dim col As Collection
If rng Is Nothing Or WorksheetFunction.CountA(rng) = 0 Then
Set CollectUniques = col
Exit Function
End If
If rng.Count = 1 Then
Set col = New Collection
col.Add Item:=CStr(rng.Value), Key:=CStr(rng.Value)
Else
varArray = rng.Value
Set col = New Collection
On Error Resume Next
For Each var In varArray
If CStr(var) <> vbNullString Then
col.Add Item:=CStr(var), Key:=CStr(var)
End If
Next var
On Error GoTo 0
End If
Set CollectUniques = col
End Function
Public Sub WriteUniquesToNewSheet()
Dim wksUniques As Worksheet
Dim rngUniques As Range, rngTarget As Range
Dim strPrompt As String
Dim varUniques As Variant
Dim lngIdx As Long
Dim colUniques As Collection
Dim WS_Count As Integer
Dim I As Integer
Set colUniques = New Collection
WS_Count = ActiveWorkbook.Worksheets.Count
For I = 3 To WS_Count
Sheets(I).Activate
Set rngTarget = Range("J19:BU500")
On Error GoTo 0
If rngTarget Is Nothing Then Exit Sub '<~ in case the user clicks Cancel
Set colUniques = CollectUniques(rngTarget)
ReDim varUniques(colUniques.Count, 1)
For lngIdx = 1 To colUniques.Count
varUniques(lngIdx - 1, 0) = CStr(colUniques(lngIdx))
Next lngIdx
Set rngUniques = Range("DZ1:DZ" & colUniques.Count)
rngUniques = varUniques
Next I
MsgBox "Finished!"
End Sub
Any help is highly appreciated. Thankyou
You need to select the correct amount of cells to fill in all data from an array. Like Range("DZ10").Resize(RowSize:=colUniques.Count)
That error probably means that colUniques is nothing and therefore has no .Count. So test if it is Nothing before you use it.
You will end up with something like below:
Public Sub WriteUniquesToNewSheet()
Dim wksUniques As Worksheet
Dim rngUniques As Range, rngTarget As Range
Dim strPrompt As String
Dim varUniques As Variant
Dim lngIdx As Long
Dim colUniques As Collection
Dim WS_Count As Integer
Dim I As Integer
Set colUniques = New Collection
WS_Count = ActiveWorkbook.Worksheets.Count
For I = 3 To WS_Count
Sheets(I).Activate
Set rngTarget = Range("J19:BU500")
'On Error GoTo 0 'this is pretty useless without On Error Resume Next
If rngTarget Is Nothing Then Exit Sub 'this is never nothing if you hardcode the range 2 lines above (therefore this test is useless)
Set colUniques = CollectUniques(rngTarget)
If Not colUniques Is Nothing Then
ReDim varUniques(colUniques.Count, 1)
For lngIdx = 1 To colUniques.Count
varUniques(lngIdx - 1, 0) = CStr(colUniques(lngIdx))
Next lngIdx
Set rngUniques = Range("DZ10").Resize(RowSize:=colUniques.Count)
rngUniques = varUniques
End If
Next I
MsgBox "Finished!"
End Sub

Copy VBA code from one sheet to all other sheets in workbook

I have code in my workbook that i need to copy to all sheets within the workbook, so when i update the code on one sheet, i dont need to copy/paste manually to all other sheets
The code is on a mastersheet called "Contents"
Alternatively, if i can get help to apply the code to all sheets from "ThisWorkbook" (I did try this option, however i could not get it to work)
This is the code i need applied to all sheets:
Private Sub CommandButton1_Click()
If ComboBox3.Value <> "" Then
Worksheets(ComboBox3.Value).Activate
ElseIf ComboBox3.Value = "" And ComboBox2.Value <> "" Then
Worksheets(ComboBox2.Value).Activate
Else:
Worksheets(ComboBox1.Value).Activate
End If
End Sub
Private Sub ComboBox2_Change()
Dim rngMenu2 As Range
Dim rngList As Range
Dim strSelected As String
Dim LastRow As Long
' check that a Menu1 has been selected
If ComboBox2.ListIndex <> -1 Then
ComboBox3.Clear
strSelected = ComboBox2.Value
LastRow = Worksheets("Contents").Range("F" & Rows.Count).End(xlUp).Row
Set rngList = Worksheets("Contents").Range("F1:F" & LastRow)
For Each rngMenu2 In rngList
If rngMenu2.Value = strSelected Then
ComboBox3.AddItem rngMenu2.Offset(, 1)
End If
Next rngMenu2
End If
End Sub
Private Sub ComboBox1_Change()
Dim rngMenu1 As Range
Dim rngList As Range
Dim strSelected As String
Dim LastRow As Long
' check that a Menu1 has been selected
If ComboBox1.ListIndex <> -1 Then
ComboBox2.Clear
ComboBox3.Clear
strSelected = ComboBox1.Value
LastRow = Worksheets("Contents").Range("D" & Rows.Count).End(xlUp).Row
Set rngList = Worksheets("Contents").Range("D1:D" & LastRow)
For Each rngMenu1 In rngList
If rngMenu1.Value = strSelected Then
ComboBox2.AddItem rngMenu1.Offset(, 1)
End If
Next rngMenu1
End If
End Sub
This is the code i have to copy code to another sheet, but it only copies to 1 sheet, how can i change this to all sheets? I would also need this to delete any existing code before copying the new code to the sheets...
I have a list of sheet names in a range
Private Sub CommandButton2_Click()
Dim CodeCopy As VBIDE.CodeModule
Dim CodePaste As VBIDE.CodeModule
Dim numLines As Integer
Dim rngList As Range
Dim LastRow As Long
LastRow = Worksheets("Contents").Range("H" & Rows.Count).End(xlUp).Row
Set rngList = Worksheets("Contents").Range("H1:H" & LastRow)
Set CodeCopy = ActiveWorkbook.VBProject.VBComponents("Sheet1").CodeModule
Set CodePaste = ActiveWorkbook.VBProject.VBComponents("Sheet40").CodeModule
End Sub
Any assistance with this would be awesome (Note: im a newbie with coding! :)
Thanks in advance!

Subscript out of range - runtime error 9

can you please advise why the below code does not select the visible sheets, but ends in a runtime error. This is driving me crazy. Thanks for any help.
Sub SelectSheets1()
Dim mySheet As Object
Dim mysheetarray As String
For Each mySheet In Sheets
With mySheet
If .Visible = True And mysheetarray = "" Then
mysheetarray = "Array(""" & mySheet.Name
ElseIf .Visible = True Then
mysheetarray = mysheetarray & """, """ & mySheet.Name
Else
End If
End With
Next mySheet
mysheetarray = mysheetarray & """)"
Sheets(mysheetarray).Select
End Sub
Long story short - you are giving a string (mysheetarray) when it is expecting array. VBA likes to get what it expects.
Long story long - this is the way to select all visible sheets:
Option Explicit
Sub SelectAllVisibleSheets()
Dim varArray() As Variant
Dim lngCounter As Long
For lngCounter = 1 To Sheets.Count
If Sheets(lngCounter).Visible Then
ReDim Preserve varArray(lngCounter - 1)
varArray(lngCounter - 1) = lngCounter
End If
Next lngCounter
Sheets(varArray).Select
End Sub
You should define Dim mySheet As Object as Worksheet.
Also, you can use an array of Sheet.Names that are visible.
Code
Sub SelectSheets1()
Dim mySheet As Worksheet
Dim mysheetarray() As String
Dim i As Long
ReDim mysheetarray(Sheets.Count) '< init array to all existing worksheets, will optimize later
i = 0
For Each mySheet In Sheets
If mySheet.Visible = xlSheetVisible Then
mysheetarray(i) = mySheet.Name
i = i + 1
End If
Next mySheet
ReDim Preserve mysheetarray(0 To i - 1) '<-- optimize array size
Sheets(mysheetarray).Select
End Sub
I have tried to explain the Sheets a little, HTH.
Note: Sheets property is defined on Workbook and on Application objects, both works and returns the Sheets-Collection.
Option Explicit
Sub SheetsDemo()
' All sheets
Dim allSheets As Sheets
Set allSheets = ActiveWorkbook.Sheets
' Filtered sheets by sheet name
Dim firstTwoSheets As Sheets
Set firstTwoSheets = allSheets.Item(Array("Sheet1", "Sheet2"))
' or simply: allSheets(Array("Sheet1", "Sheet2"))
' Array("Sheet1", "Sheet2") is function which returns Variant with strings
' So you simply need an array of sheet names which are visible
Dim visibleSheetNames As String
Dim sh As Variant ' Sheet class doesn't exist so we can use Object or Variant
For Each sh In allSheets
If sh.Visible Then _
visibleSheetNames = visibleSheetNames & sh.Name & ","
Next sh
If Strings.Len(visibleSheetNames) > 0 Then
' We have some visible sheets so filter them out
visibleSheetNames = Strings.Left(visibleSheetNames, Strings.Len(visibleSheetNames) - 1)
Dim visibleSheets As Sheets
Set visibleSheets = allSheets.Item(Strings.Split(visibleSheetNames, ","))
visibleSheets.Select
End If
End Sub