Loop through checkboxes on a sheet - excel

How would I create the following as a Loop.
Basically the first list to loop would be selectStatus, selectSite, These are check boxes on a sheet. (The below code only includes two but the full macro has about 60 to loop)
The second loop would be the values "Header 1", "Header 2", etc. so they would both loop and change together. The first one being the checkbox name and the second being a corresponding SQL header which I want at the end to create a string.
Sub TEST2()
If Sheets("controlSheet").selectStatus.Value = True Then
a = "Header 1, "
Else
a = ""
End If
If Sheets("controlSheet").selectSite.Value = True Then
a = a + "Header 2, "
Else
a = a + ""
End If
End Sub

This should handle ActiveX checkboxes.
NOTE: This requires your checkboxes are indexed correctly (i.e., the first one by index will correspond to "Header 1", the second with "Header 2", the nth with "Header n", etc...). If they are out of order, you'd need additional logic to control for that (see the other answer for a good solution if that is the case).
Option Explicit
Sub LoopActiveXCheckBoxes()
Dim ws As Worksheet
Dim obj As OLEObject
Dim cb As CheckBox
Dim i As Long
Dim a As String
Set ws = Sheets("controlSheet")
For Each obj In ws.OLEObjects
If TypeName(obj.Object) = "CheckBox" Then
i = i + 1
If obj.Object.Value = True Then
a = a & "Header " & CStr(i) & ","
End If
End If
Next
If Len(a) > 0 Then a = Left(a, Len(a) - 1)
End Sub
For Form Control checkboxes, this would work but I'm pretty sure you're using ActiveX.
Sub LoopCheckBoxes()
Dim ws As Worksheet
Dim cb As CheckBox
Dim i As Long
Dim a As String
Set ws = Sheets("controlSheet")
For Each cb In ws.CheckBoxes
i = i + 1
If cb.Value = 1 Then
a = a & "Header " & CStr(i) & ","
End If
Next
If Len(a) > 0 Then a = Left(a, Len(a) - 1)
End Sub

Here's one header where you can create an object to hold a list of the mapping between control name and header name. Let me know of any questions.
Dim oDictHeaders As Object
Function GetHeaders() As Object
If oDictHeaders Is Nothing Then
Set oDictHeaders = CreateObject("Scripting.Dictionary")
oDictHeaders("SelectSite") = "Header 1"
oDictHeaders("SelectStatus") = "Header 2"
oDictHeaders("SelectOther") = "Header 3"
End If
Set GetHeaders = oDictHeaders
End Function
Function GetListOfHeaders() As String
Dim sOutput As String
Dim oDict As Object
Dim ctl As Object
sOutput = ""
Set oDict = GetHeaders()
For Each ctl In Sheet1.OLEObjects
Debug.Print TypeName(ctl.Object)
If TypeName(ctl.Object) = "CheckBox" Then
If ctl.Object.Value = True Then
sOutput = sOutput & ", " & oDict(ctl.Name)
End If
End If
Next ctl
GetListOfHeaders = Mid(sOutput, 2)
End Function
Sub Test()
MsgBox (GetListOfHeaders())
End Sub

Related

Can we attach multiple images to a useform in VBA, save in a folder with a specific naming convention and retrieve later using that name?

I have a VBA project where I need to create a userform on which there should be an attachment button to select multiple images and save them in a folder with a specific name. Later, if a person looks up that name from the search box, it should call all the information saved along with the images. The names should be as follows Sh-0001-01 (where 0001 represents invoice number and 01 denotes attachment number).
I have got a file from another forum that can load images into the image box and scroll across them but there is no mechanism to add new images except copying new images to the back-end folder. And also, no functionality to save attachments with a specific name and look them up using that name.
The outcome is attached as an image. The example code file can be accessed via this link:
https://drive.google.com/file/d/1HXLjDIpjNmgxLxegYiexxEykh4f_54sY/view?usp=sharing
As it was mandatory by Stackoverflow to include a sample code, here is part of the code that is in the file in the drive:
Public Const fPath As String = "C:\Test\"
Sub LaunchForm()
UserForm1.Show
End Sub
Function PhotoNum(numx As Integer) As String
Dim PhotoNames As String, iFile As String
Dim i As Integer
Dim ArrayPhoto() As Variant
iFile = "*.*"
PhotoNames = Dir(fPath & iFile)
i = 0
Do Until PhotoNames = ""
i = i + 1
ReDim Preserve ArrayPhoto(1 To i)
ArrayPhoto(i) = PhotoNames
PhotoNames = Dir
Loop
PhotoNum = ArrayPhoto(numx)
End Function
Function MaxPhoto() As Integer
Dim PhotoNames As String, iFile As String
Dim i As Integer
Dim ArrayPhoto() As Variant
iFile = "*.*"
PhotoNames = Dir(fPath & iFile)
i = 0
Do Until PhotoNames = ""
i = i + 1
ReDim Preserve ArrayPhoto(1 To i)
ArrayPhoto(i) = PhotoNames
PhotoNames = Dir
Loop
MaxPhoto = UBound(ArrayPhoto)
End Function
Any help is appreciated.
Please, try the next way. A text box named "tbOrder" must exist. In it the order/invoice number must be entered (manually or by code). The rest of controls are the one used in your sent testing workbook. Please, copy the next code in the form code module. Only a sub showing the form should exist in a standard module. A new button (btAttach) to add attachment has been added and a check box (chkManyAtt) where to specify the multiple selection option:
Option Explicit
Private Const fPath As String = "C:\test\"
Private photoNo As Long, arrPhoto() As Variant, boolNoEvents As Boolean, prevVal As Long, boolFound As Boolean
Private boolManyAttch As Boolean
Private Sub btAttach_Click()
If Len(tbOrder.Text) <> 7 Then MsgBox "An invoice number is mandatory in its specific text box (7 digits long)": Exit Sub
Dim noPhotos As Long, runFunc As String
runFunc = bringPicture(Left(tbOrder.Text, 7), True)
If Not boolFound Then noPhotos = -1
Dim sourceFile As String, destFile As String, attName As String, strExt As String, i As Long
With Application.FileDialog(msoFileDialogFilePicker)
.Title = "Please, select the picture to be added as attachment for invoice " & Me.tbOrder.Text & " (" & photoNo & ")"
.AllowMultiSelect = IIf(boolManyAttch = True, True, False)
.Filters.Add "Picture Files", "*.jpg", 1
If .Show = -1 Then
For i = 1 To .SelectedItems.Count
sourceFile = .SelectedItems(i): 'Stop
attName = Me.tbOrder.Text & "-" & Format(IIf(noPhotos = -1, 1, photoNo + 1), "00")
strExt = "." & Split(sourceFile, ".")(UBound(Split(sourceFile, ".")))
destFile = fPath & attName & strExt
FileCopy sourceFile, destFile
ReDim Preserve arrPhoto(IIf(noPhotos = -1, 0, UBound(arrPhoto) + 1)): noPhotos = 0
arrPhoto(UBound(arrPhoto)) = attName & strExt
photoNo = photoNo + 1
Next i
Else
Exit Sub
End If
End With
Me.TextBox2.Text = photoNo: Me.TextBox2.Enabled = False
Me.TextBox1.Text = photoNo
End Sub
Private Sub chkManyAtt_Click()
If Me.chkManyAtt.Value Then
boolManyAttch = True
Else
boolManyAttch = False
End If
End Sub
Private Sub CommandButton1_Click() 'Prev button
Dim currPic As Long
currPic = Me.TextBox1.Value
If currPic > 1 Then
Me.Image1.Picture = LoadPicture(fPath & arrPhoto(currPic - 2))
boolNoEvents = True 'stop the events when TextBox1 is changed
Me.TextBox1.Text = currPic - 1
prevVal = Me.TextBox1.Value
boolNoEvents = False 'restart events
End If
End Sub
Private Sub CommandButton2_Click() 'Next button
Dim currPic As Long
currPic = Me.TextBox1.Value
If currPic < photoNo Then
Me.Image1.Picture = LoadPicture(fPath & arrPhoto(currPic))
boolNoEvents = True
Me.TextBox1.Text = currPic + 1
prevVal = Me.TextBox1.Value
boolNoEvents = False
Else
MsgBox "Please, select a valid image number..."
End If
End Sub
Private Sub tbOrder_Change() 'the textbox where to input the order/invoice nubmer
Dim firstPict As String
If Len(tbOrder.Text) >= 7 Then
photoNo = 0: Erase arrPhoto 'clear the variable keeping the number of found photos and the array keeping them
firstPict = bringPicture(Left(tbOrder.Text, 7)) 'to make it working even if you paste "Sh-0002-20"
If firstPict <> "" Then 'determining the first picture to be placed
With Me.Image1
.Picture = LoadPicture(fPath & firstPict)
.PictureSizeMode = fmPictureSizeModeZoom
End With
boolNoEvents = True 'avoiding the event to be triggeret twice
Me.TextBox1.Text = 1
With Me.TextBox2
.Enabled = True
.Text = photoNo
.Enabled = False
End With
boolNoEvents = False
Else
Me.Image1.Picture = LoadPicture(vbNullString) 'clear the picture if no order/invoice have been written in the text box
Me.TextBox2.Text = "": Me.TextBox1.Text = ""
End If
End If
End Sub
Function bringPicture(strName As String, Optional boolAttach As Boolean = False) As String
Dim PhotoNames As String, arrPh, noPict As Long, firstPict As String, ph As Long
PhotoNames = Dir(fPath & strName & "*.*") 'find the first photo with the necessary pattern name
If boolAttach Then
ReDim arrPhoto(0): photoNo = 0
Else
ReDim arrPhoto(photoNo) 'firstly ReDim the array
End If
boolFound = False
Do While PhotoNames <> ""
boolFound = True
arrPhoto(photoNo) = PhotoNames: photoNo = photoNo + 1
ReDim Preserve arrPhoto(photoNo)
PhotoNames = Dir()
Loop
If photoNo > 0 Then
ReDim Preserve arrPhoto(photoNo - 1) 'eliminate the last empty array element
bringPicture = arrPhoto(0) 'return the first photo in the array
End If
End Function
Private Sub TextBox1_Change() 'manually change the picture number
If Not boolNoEvents Then 'to not be treggered when changed by code
If IsNumeric(Me.TextBox1.Value) Then 'to allow only numbers
If Len(Me.TextBox1.Value) >= Len(CStr(photoNo)) Then 'to allow numbers less or equal with the maximum available
If CLng(TextBox1.Text) > photoNo Then
MsgBox "Select valid image number"
boolNoEvents = True
Me.TextBox1.Text = prevVal
boolNoEvents = False
Else
Me.Image1.Picture = LoadPicture(fPath & arrPhoto(Me.TextBox1.Value - 1))
Me.Image1.PictureSizeMode = fmPictureSizeModeZoom
End If
prevVal = Me.TextBox1.Value
End If
Else
Me.TextBox1.Text = ""
End If
End If
End Sub
If something not clear enough, please do not hesitate to ask for clarifications.

Retrieve data from a workbook to a userform in a different work book

I have an Excel work book which is acting as a database and a UserForm which acts as a UI. Both are in different workbooks.
I want to populate the UserForm with data from Excel workbook .
Private Sub CommandButton4_Click()
Dim n As Long, i As Long
n = 0
Dim mydata1 As Workbook
Set mydata1 = Workbooks.Open("\\NTSYDFSP150\Shared\fmd\credit\LEM_Reports\SV References\SV Entry Form Input.xlsx")
mydata1.Worksheets("sheet1").Activate
mydata1.Worksheets("sheet1").Range("A1").Select
n = Worksheets("sheet1").Range("a1").CurrentRegion.Rows.Count
For i = 2 To n
If Trim(Sheet1.Cells(i, 1)) <> Trim(UserForm1.TextBox157.Text) And i = n Then
MsgBox ("Name not found")
End If
If Trim(Sheet1.Cells(i, 1)) = Trim(UserForm1.TextBox157.Text) Then
UserForm1.TextBox1.Text = Sheet1.Cells(i, 1)
Exit For
End If
Next i
mydata1.Save
mydata1.Close
MsgBox "Data searched successfully", 0, vbNullString
End Sub
Issue :
When I run the code am not able to retrieve data from workbook Excel database.
Sheet1.Cells(i, 1): - This field still refers to Shee1 from User form work book while it should be referring to work book at shared drive location since I had activated and opened that .
Note: n is calculated correctly.
I cleaned up your code and qualified the ranges where necessary. Not qualifying the ranges is most likely the error here. Example: Worksheets("sheet1").Range("a1"). ... needs to be mydata1.Worksheets("sheet1").Range("a1"). .... Try the following code:
Private Sub CommandButton4_Click()
Dim n As Long, i As Long
n = 0
Dim mydata1 As Workbook
Set mydata1 = Workbooks.Open("\\NTSYDFSP150\Shared\fmd\credit\LEM_Reports\SV References\SV Entry Form Input.xlsx")
n = mydata1.Worksheets("sheet1").Range("a1").CurrentRegion.Rows.Count
For i = 2 To n
If Trim(mydata1.Sheet1.Cells(i, 1)) <> Trim(UserForm1.TextBox157.Text) And i = n Then
MsgBox ("Name not found")
End If
If Trim(mydata1.Sheet1.Cells(i, 1)) = Trim(UserForm1.TextBox157.Text) Then
UserForm1.TextBox1.Text = mydata1.Sheet1.Cells(i, 1)
Exit For
End If
Next i
mydata1.Save
mydata1.Close
MsgBox "Data searched successfully", 0, vbNullString
End Sub
Note that activating the workbook and .Selecting a Range is not necessary in this case (so I deleted it) and should be avoided in general (see comment above for additional advice).
This is just a suggested way to prevent opening another workbook:
Private Sub CommandButton4_Click()
Dim wbPath As String: wbPath = "\\NTSYDFSP150\Shared\fmd\credit\LEM_Reports\SV References\"
Dim wbName As String: wbName = "SV Entry Form Input.xlsx"
Dim wsName As String: wsName = "sheet1"
Dim arrList As Object: Set arrList = CreateObject("System.Collections.ArrayList")
Dim lr As Long, x As Long
'Get the last row from A column, notice we need R1C1 notation for Excel4Macro
lr = ExecuteExcel4Macro("MATCH(""zzz"",'" & wbPath & "[" & wbName & "]" & wsName & "'!C1)")
'Let's use an ArrayList to get our validation list
For x = 2 To lr
arrList.Add Trim(ExecuteExcel4Macro("'" & wbPath & "[" & wbName & "]" & wsName & "'!R" & x & "C1"))
Next x
'Check if ArrayList contains your lookup value
If arrList.Contains(Trim(UserForm1.TextBox157.Text)) Then
UserForm1.TextBox1.Text = UserForm1.TextBox157.Text
Else
MsgBox ("Name not found")
End If
MsgBox "Data searched successfully"
End Sub

How to get all item selected into ListBox ( Multiple Selection ) in VBA

I would like to select multiple data from a listbox
The code below work fine for Single Selection: 0 -fmMultiSelectSingle
Private Sub ListBox1_Click()
Dim Msg As String
Dim i As Integer
Msg = "You selected:" & vbNewLine
For i = 1 To ListBox1.ListCount
If ListBox1.Selected(i) Then
Msg = Msg & ListBox1.List(i) & vbNewLine
End If
Next i
MsgBox Msg
ListBox1.Selected(0) = False
End Sub
The messagebox displays me the slected item, but if I switch the MultiSelect option to:
1 - fmMultiSelectMulti or 2 - fmMultiSelectExtended, the previous code isn't working: The message box displays nothing.
Am I doing something wrong?
The event should be _Change and not _Click, as far as it does not enter it, in the case of fmMultiSelectExtended due to some strange reason. Or try the other built-in events in the VBE, available from the dropdown:
Private Sub ListBox1_Change()
Dim myMsg As String
Dim i As Long
For i = 0 To ListBox1.ListCount - 1
If ListBox1.Selected(i) Then
myMsg = myMsg & ListBox1.List(i)
End If
Next i
Debug.Print myMsg
End Sub
Just consider the fact, that if you select 3 values after each other, every time there would be only 1 selected value. Thus, you would get 3 different sets of data in the immediate window. Like this:
For this ListBox:
Following Code to Store all value of selected items in listbox
Public Function listASIN() As String
Dim ctl As Control
Dim strASIN As String
Set ctl = Me!lstASIN
strASIN = ""
' Now select what records from listbox
If ctl.ItemsSelected.Count > 0 Then
i = 1
For Each varItem In ctl.ItemsSelected
strASIN = strASIN & ctl.ItemData(varItem) & ","
i = i + 1
Next varItem
Else
Exit Function
End If
'Remove Last "," from ASIN list
strASIN = Left(strASIN, Len(strASIN) - 1)
listASIN = strASIN
End Function

Merge 2 Excel files with different columns, using a user form to select files and then column mapping

I need to merge two Excel files, but only certain columns from each. I need to use a userform to select the two files to merge and then also use column mapping to select which columns from each sheet need appear where in the new output sheet.
So far I have this.
Private Sub AddFilesButton_Click()
Dim arrFiles As Variant
On Error GoTo ErrMsg
'Let the user choose the files they want to merge
#If Mac Then
arrFiles = Select_File_Or_Files_Mac()
#Else
arrFiles = Application.GetOpenFilename("Excel Files (*.xls; *.xlsx), *.xls;*.xlsx", 1, "Choose Excel Files", "Select", True)
#End If
If IsNull(arrFiles) Or UBound(arrFiles) = -1 Then
MsgBox "Please choose at least one Excel file"
Else
For Each file In arrFiles
FilesListBox.AddItem file
Next file
MergeButton.Enabled = True
End If
ErrMsg:
If Err.Number <> 0 Then
MsgBox "There was an error. Please try again. [" & Err.Description & "]"
End If
End Sub
Private Sub CancelButton_Click()
Unload Me
End Sub
Private Sub MergeButton_Click()
Dim fileName As Variant
Dim wb As Workbook
Dim s As Sheet1
Dim thisSheet As Sheet1
Dim lastUsedRow As Range
Dim columnMap As Collection
Dim filePath As Variant
Dim dataRange As Range
Dim insertAtRowNum As Integer
Dim outColName As String
Dim colName As String
Dim fromRange As String
Dim fromRangeToCopy As Range
Dim toRange As String
On Error GoTo ErrMsg
Application.ScreenUpdating = False
Set thisSheet = ThisWorkbook.ActiveSheet
For i = 0 To FilesListBox.ListCount - 1
fileName = FilesListBox.List(i, 0)
'Get the map of columns for this file
Set columnMap = MapColumns(fileName)
'Open the spreadsheet in ReadOnly mode
Set wb = Application.Workbooks.Open(fileName, ReadOnly:=True)
For Each sourceSheet In wb.Sheets
'Get the used range (i.e. cells with data) from the opened spreadsheet
If firstRowHeaders And i > 0 Then 'Only include headers from the first spreadsheet
Dim mr As Integer
mr = wb.ActiveSheet.UsedRange.Rows.Count
Set dataRange = wb.ActiveSheet.UsedRange.Offset(1, 0).Resize(mr - 1)
Else
Set dataRange = wb.ActiveSheet.UsedRange
End If
For Each col In dataRange.Columns
'Get corresponding output column. Empty string means no mapping
colName = GetColName(col.Column)
outColName = GetOutputColumn(columnMap, colName)
If outColName <> "" Then
fromRange = colName & 1 & ":" & colName & dataRange.Rows.Count
Set fromRangeToCopy = dataRange.Range(fromRange)
fromRangeToCopy.Copy
toRange = outColName & insertAtRowNum & ":" & outColName & (insertAtRowNum + fromRangeToCopy.Rows.Count - 1)
thisSheet.Range(toRange).PasteSpecial
End If
Next col
insertAtRowNum = insertAtRowNum + dataRange.Rows.Count
Next sourceSheet
Application.CutCopyMode = False
Next i
ThisWorkbook.Save
Set wb = Nothing
#If Mac Then
'Do nothing. Closing workbooks fails on Mac for some reason
#Else
'Close the workbooks except this one
Dim file As String
For i = 0 To FilesListBox.ListCount - 1
file = FilesListBox.List(i, 0)
file = Right(file, Len(file) - InStrRev(file, Application.PathSeparator, , 1))
Workbooks(file).Close SaveChanges:=False
Next i
#End If
Application.ScreenUpdating = True
Unload Me
ErrMsg:
If Err.Number <> 0 Then
MsgBox "There was an error. Please try again. [" & Err.Description & "]"
End If
End Sub
Function MapColumns(fileName As Variant) As Object
Dim colMap As New Collection
Select Case fileName
Case "ExcelFile1.xlsx"
colMap.Add Key:="C", Item:="A"
colMap.Add Key:="D", Item:="B"
colMap.Add Key:="E", Item:="C"
colMap.Add Key:="I", Item:="D"
Case "ExcelFile2.xlsx"
colMap.Add Key:="B", Item:="F"
colMap.Add Key:="J", Item:="G"
colMap.Add Key:="H", Item:="H"
colMap.Add Key:="C", Item:="I"
End Select
Set MapColumns = colMap
End Function
Function GetOutputColumn(columnMap As Collection, col As String) As String
Dim outCol As String
outCol = ""
If columnMap.Count > 0 Then
outCol = columnMap.Item(col)
End If
GetOutputColumn = outCol
End Function
'From: http://www.mrexcel.com/forum/excel-questions/16444-getting-column-name-given-column-number.html
Function GetColName(ColumnNumber)
FuncRange = Cells(1, ColumnNumber).AddressLocal(False, False) 'Creates Range (defaults Row to 1) and retuns Range in xlA1 format
FuncColLength = Len(FuncRange) 'finds length of range reference
GetColName = Left(FuncRange, FuncColLength - 1) 'row always "1" therefore take 1 away from string length and you are left with column ref
End Function
'From: http://msdn.microsoft.com/en-us/library/office/hh710200%28v=office.14%29.aspx#odc_xl4_ta_ProgrammaticallySelectFileforMac_DifferencesWindowsandMac
Function Select_File_Or_Files_Mac() As Variant
Dim MyPath As String
Dim MyScript As String
Dim MyFiles As String
Dim MySplit As Variant
Dim N As Long
Dim Fname As String
Dim mybook As Workbook
On Error Resume Next
MyPath = MacScript("return (path to documents folder) as String")
'Or use MyPath = "Macintosh HD:Users:Ron:Desktop:TestFolder:"
' In the following statement, change true to false in the line "multiple
' selections allowed true" if you do not want to be able to select more
' than one file. Additionally, if you want to filter for multiple files, change
' {""com.microsoft.Excel.xls""} to
' {""com.microsoft.excel.xls"",""public.comma-separated-values-text""}
' if you want to filter on xls and csv files, for example.
MyScript = _
"set applescript's text item delimiters to "","" " & vbNewLine & _
"set theFiles to (choose file of type " & _
" {""com.microsoft.Excel.xls"",""org.openxmlformats.spreadsheetml.sheet""} " & _
"with prompt ""Please select a file or files"" default location alias """ & _
MyPath & """ multiple selections allowed true) as string" & vbNewLine & _
"set applescript's text item delimiters to """" " & vbNewLine & _
"return theFiles"
MyFiles = MacScript(MyScript)
On Error GoTo 0
MySplit = False 'Assume no files = cancel
If MyFiles <> "" Then
With Application
.ScreenUpdating = False
.EnableEvents = False
End With
MySplit = Split(MyFiles, ",")
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
End If
Select_File_Or_Files_Mac = MySplit
End Function
Function bIsBookOpen(ByRef szBookName As String) As Boolean
' Contributed by Rob Bovey
On Error Resume Next
bIsBookOpen = Not (Application.Workbooks(szBookName) Is Nothing)
End Function

Need to write values with VBA from autocad into an excel sheet

I am using VBA in Autocad in order to count blocks in drawings.
With some search through the internet and some tries I have managed to complete the following code and count all blocks in any drawing, or by layer or the selected ones.
Sub BlockCount_Test()
dispBlockCount "COUNT_ALL"
dispBlockCount "COUNT_BY_LAYER"
dispBlockCount "COUNT_BY_FILTER"
End Sub
Sub dispBlockCount(ByVal strAction As String)
On Error Resume Next
Dim objBlkSet As AcadSelectionSet
Dim objBlkRef As AcadBlockReference
Dim strBlkNames() As String
Dim iGpCode(0) As Integer
Dim vDataVal(0) As Variant
Dim iSelMode As Integer
Dim iBlkCnt As Integer
iGpCode(0) = 0
vDataVal(0) = "INSERT"
iSelMode = 0 '|-- Selection Modes (0 = Select All, 1 = Select On Screen) --|
Set objBlkSet = getSelSet(iGpCode, vDataVal, iSelMode)
If objBlkSet.Count <> 0 Then
Select Case strAction
Case "COUNT_ALL"
ReDim strBlkNames(objBlkSet.Count - 1)
iBlkCnt = 0
For Each objBlkRef In objBlkSet
strBlkNames(iBlkCnt) = objBlkRef.Name
iBlkCnt = iBlkCnt + 1
Next
MsgBox getUniqBlockCount(strBlkNames), , "Count All"
Case "COUNT_BY_LAYER"
Dim objCadEnt As AcadEntity
Dim vBasePnt As Variant
ThisDrawing.Utility.GetEntity objCadEnt, vBasePnt, "Pick a block reference:"
If Err.Number <> 0 Then
MsgBox "No block references selected."
objBlkSet.Delete
Exit Sub
Else
If objCadEnt.ObjectName = "AcDbBlockReference" Then
Dim objCurBlkRef As AcadBlockReference
Dim strLyrName As String
iBlkCnt = 0
Set objCurBlkRef = objCadEnt
strLyrName = objCurBlkRef.Layer
For Each objBlkRef In objBlkSet
If StrComp(objBlkRef.Layer, strLyrName, vbTextCompare) = 0 Then
ReDim Preserve strBlkNames(iBlkCnt)
strBlkNames(iBlkCnt) = objBlkRef.Name
iBlkCnt = iBlkCnt + 1
End If
Next
MsgBox getUniqBlockCount(strBlkNames), , "Count by Layer"
Else
ThisDrawing.Utility.prompt "The selected object is not a block reference."
End If
End If
Case "COUNT_BY_FILTER"
Dim strFilter As String
iBlkCnt = 0
strFilter = ThisDrawing.Utility.GetString(False, "Enter a filter option:")
If strFilter <> "" Then
For Each objBlkRef In objBlkSet
If UCase(objBlkRef.Name) Like UCase(strFilter) Then
ReDim Preserve strBlkNames(iBlkCnt)
strBlkNames(iBlkCnt) = objBlkRef.Name
iBlkCnt = iBlkCnt + 1
End If
Next
MsgBox getUniqBlockCount(strBlkNames), , "Count by Filter"
Else
ThisDrawing.Utility.prompt "Search criteria should not be empty."
End If
Case Else
ThisDrawing.Utility.prompt "Invalid action mode."
End Select
Else
ThisDrawing.Utility.prompt "No block references were found."
End If
objBlkSet.Delete
If Err.Number <> 0 Then
ThisDrawing.Utility.prompt Err.Description
End If
End Sub
Function getSelSet(ByRef iGpCode() As Integer, vDataVal As Variant, iSelMode As Integer) As AcadSelectionSet
Dim objSSet As AcadSelectionSet
Set objSSet = ThisDrawing.SelectionSets.Add("EntSet")
Select Case iSelMode
Case 0
objSSet.Select acSelectionSetAll, , , iGpCode, vDataVal
Case 1
ReSelect:
objSSet.SelectOnScreen iGpCode, vDataVal
If objSSet.Count = 0 Then
Dim iURep As Integer
iURep = MsgBox("No entities selected, Do you want to select again?", _
vbYesNo, "Select Entity")
If iURep = 6 Then GoTo ReSelect
objSSet.Delete
Set getSelSet = Nothing
Exit Function
End If
Case Else
ThisDrawing.Utility.prompt "Invalid selection mode...."
End Select
Set getSelSet = objSSet
End Function
Function getUniqBlockCount(ByRef strBlkNames() As String) As String
Dim strUniqBlkNames() As String
Dim iBlkCount() As Integer
Dim iArIdx1, iArIdx2 As Integer
iArIdx1 = 0: iArIdx2 = 0
For iArIdx1 = LBound(strBlkNames) To UBound(strBlkNames)
If iArIdx1 = 0 Then
ReDim strUniqBlkNames(iArIdx2)
strUniqBlkNames(iArIdx2) = strBlkNames(iArIdx1)
iArIdx2 = iArIdx2 + 1
End If
Dim iUnqArIdx As Integer
Dim blUniq As Boolean
blUniq = True
For iUnqArIdx = LBound(strUniqBlkNames) To UBound(strUniqBlkNames)
If StrComp(strBlkNames(iArIdx1), strUniqBlkNames(iUnqArIdx), vbTextCompare) = 0 Then
blUniq = False
Exit For
End If
Next
If blUniq Then
ReDim Preserve strUniqBlkNames(iArIdx2)
strUniqBlkNames(iArIdx2) = strBlkNames(iArIdx1)
iArIdx2 = iArIdx2 + 1
End If
Next
iArIdx1 = 0: iArIdx2 = 0
For iArIdx1 = LBound(strUniqBlkNames) To UBound(strUniqBlkNames)
For iArIdx2 = LBound(strBlkNames) To UBound(strBlkNames)
If StrComp(strBlkNames(iArIdx2), strUniqBlkNames(iArIdx1), vbTextCompare) = 0 Then
ReDim Preserve iBlkCount(iArIdx1)
iBlkCount(iArIdx1) = iBlkCount(iArIdx1) + 1
End If
Next
Next
For iUnqArIdx = LBound(iBlkCount) To UBound(iBlkCount)
strUniqBlkNames(iUnqArIdx) = strUniqBlkNames(iUnqArIdx) & vbTab & vbTab & vbTab & iBlkCount(iUnqArIdx) & vbCrLf
Next
Dim strTitle, strBlkCount As String
strBlkCount = Join(strUniqBlkNames)
strTitle = "Block Name" & vbTab & vbTab & "Count" & vbCrLf
strTitle = strTitle & String(14, "-") & vbTab & vbTab & String(8, "-") & vbCrLf
getUniqBlockCount = strTitle & strBlkCount
End Function
My aim is to take these block numbers and insert them automatically in an excel sheet and in a certain sheet and cells.
Can someone help me find a solution to this problem?
I somehow managed to call an excel sheet but I am currently lost on how to put the block counts in the right position.
i.e. Let's say that I want them in a list as they present on the table I get from the count in my code, how could I achieve this?
P.S. I am new here and if you need any more info I would gladly add any more information needed in order to find a solution.
Thanks in advance
Georgia
I don't use AutoCad VBA myself, but based on the simple nature of your question, my guess is that this may help you on the road:
If you want to create a new Excel application:
Dim oApp_Excel as Excel.Application
Dim oBook as Excel.workbook
Set oApp_Excel = CreateObject("EXCEL.APPLICATION")
set oBook = oApp_Excel.workbooks.add
oBook.sheets("<Name>").cells(<Counter>, <Column_Number>).value = <BlockNr (based on counter)>
oBook.SaveAs(<Path>)
oBook.close
oApp_Excel.quit
set oBook = nothing
You can place the values in any cell or form you want; these are the basics of Excel VBA.
Another way is to load you BlockNumbers in an array first (in your current code) and then filling in values. This way you can set a range dynamically and load all the data from the array into the range at once.
I hope that I didn't misunderstand your question and that my reply serves your purpose.
'Create new excel instance.
Set excelApp = CreateObject("Excel.Application")
If err <> 0 Then
MsgBox "Could not start Excel!", vbExclamation, "Warning"
End
Else
excelApp.Visible = True
excelApp.ScreenUpdating = False
'Add a new workbook and set the objects.
Set wkbObj = excelApp.Workbooks.Add(1)
Set shtObj = excelApp.Worksheets(1)
shtObj.Name = "Measured Polylines"
With shtObj.Range("A1:D1")
.Font.Bold = True
.Autofilter
End With

Resources