My drawing contain 3 layers. Each of the layers contain polylines.
I need to count the total number of elements inside every layer using VBA
you can try this
Option Explicit
Sub test()
Dim myLayer As AcadLayer
For Each myLayer In ThisDrawing.Layers
MsgBox "Number of LWPolylines in layer '" & myLayer.Name & "' is: " & GetEntityTypeNumberInLayer("LWPOLYLINE", myLayer.Name)
Next myLayer
End Sub
Function GetEntityTypeNumberInLayer(entityType As String, layerName As String) As Long
Dim acSelSet As AcadSelectionSet
Dim grpCode(1) As Integer
Dim dataVal(1) As Variant
grpCode(0) = 0: dataVal(0) = entityType 'this will filter for the entity type passed with "entityType"
grpCode(1) = 8: dataVal(1) = layerName 'this will filter for layer with name as the one passed with "layerName" argument
Set acSelSet = CreateSelectionSet("sset", ThisDrawing) 'create a selection set via a proper function
acSelSet.Select acSelectionSetAll, , , grpCode, dataVal ' fill it with all elements filtered as above: LWPolylines in layer with name passed via "layername" argument
GetEntityTypeNumberInLayer = acSelSet.Count 'count the numbers of element in the selectionset
acSelSet.Delete ' delete the selection set
End Function
Function CreateSelectionSet(selsetName As String, Optional acDoc As Variant) As AcadSelectionSet
'this function returns a selection set with the given name
'if a selectionset with the given name already exists, it returns that selectionset after clearing it
'if a selectionset with the given name doesn't exist, it creates a new selectionset and returns it
Dim acSelSet As AcadSelectionSet
If IsMissing(acDoc) Then Set acDoc = ThisDrawing
On Error Resume Next
Set acSelSet = acDoc.SelectionSets.Item(selsetName) 'try to get an exisisting selection set
On Error GoTo 0
If acSelSet Is Nothing Then Set acSelSet = acDoc.SelectionSets.Add(selsetName) 'if unsuccsessful, then create it
acSelSet.Clear 'cleare the selection set
Set CreateSelectionSet = acSelSet
End Function
Related
I am trying to make a function that looks at an image, and return the X pixel value.
When i run the code, it throws an error on the Int1=CInt(Xdim) line, saying "Type Mismatch (10080)"
If i hard-code the value i am testing into Xdim, it works fine.
Function ImgXDim(filename As String) As Integer ' Finds the X dimension in pixels of a loaded image
Dim objShell As Object
Dim objFolder As Object
Dim objFile As Object
Dim ImgSize As String
Dim Int1 As Integer
Dim Xdim As String
Dim strarray() As String
Set objShell = CreateObject("Shell.Application")
Set objFolder = objShell.NameSpace(MacroDir & "\PICS\")
Set objFile = objFolder.ParseName(filename)
ImgSize = objFile.ExtendedProperty("Dimensions") ' Returns string of "700 x 923"
strarray = Split(ImgSize, " x ") ' Split into 2 strings of "700" and "923"
Xdim = CStr(strarray(0)) ' Force Xdim to be a string of "700"
Int1 = CInt(Xdim) ' Convert Xdim to an integer
ImgXDim = Int1 ' Return Integer
End Function
First check if value can be converted to an integer:
If IsNumeric(Trim(Xdim)) then
Int1 = CInt(Xdim)
else
'for debug purposes
MsgBox ("XDim non-numeric or empty")
End If
Ok, i couldnt find what character was causing the issue, so i used this loop of code to pull out only numbers, and it seems to work.
For X = 1 To Len(Xdim)
If IsNumeric(Mid(Xdim, X, 1)) = True Then
holder = holder & Mid(Xdim, X, 1)
End If
Next X
Here the WIA version:
Function ImgXDim(filename As String) As Long
Dim imgWIA as New WIA.ImageFile 'Early Binding needs a reference to Windows Image Aquisition Library in VBA-Ide->Tools->References
'Dim imgWIA as Object 'Late Bound Version
'Set imgWIA = CreateObject("WIA.ImageFile")
imgWIA.LoadFile MacroDir & "\PICS\" & filename
ImgXDim = imgWIA.Width ' use .Height for height
End Function
As you see, just three lines of code and returns a long, not a string that needs parsing.
Useful functions for resize, rotate and more.
Also useful if you want to display Tiffs in a picture control (page by page) and more.
I have a standard user defined function that concationates all the unique values. What I am trying to do is to perform this function on a range that satisfies a condition.
Function ConcatUniq(xRg As Range, xChar As String) As String
'updateby Extendoffice 20151228
Dim xCell As Range
Dim xDic As Object
Set xDic = CreateObject("Scripting.Dictionary")
For Each xCell In xRg
xDic(xCell.Value) = Empty
Next
ConcatUniq = Join$(xDic.Keys, xChar)
Set xDic = Nothing
End Function
Lets make an example:
If we have the following data:
A1:A5 = {1,2,2,4,1}
B1:B5 = {"group1", "group1","group1", "group2", "group2"}
C1 = "group1"
Now I want to find the unique values using the ConcatUniq function for all numbers that are in group1. Usually, if I want to perform another function for example the median I would do the following:
=MEDIAN(IF(B1:B5=C1,A1:A5))
Activate it using cntrl shift enter which gives 2 (create an array function from it).
For some reasons this does not work in combination with a user defined function.
=ConcatUniq(IF(B1:B5=C1,A1:A5)," ")
Desired result:
1 2
Does someone know how I could fix this problem?
You need to use ParamArray to accommodate array returned from Excel's array formula. As ParamArray should always be the last one, so your method signature will change.
This will work with =ConcatUniq(" ",IF(B1:B5=C1,A1:A5)) on CTRL + SHIFT + ENTER
Public Function ConcatUniq(xChar As String, ParamArray args())
Dim xDic As Object
Dim xVal
Set xDic = CreateObject("Scripting.Dictionary")
For Each xVal In args(0)
If Not Not xVal Then
xDic(xVal) = Empty
End If
Next
ConcatUniq = Join$(xDic.Keys, xChar)
End Function
Perhaps something like this:
Public Function ConcatUniq(ByVal rangeOrArray As Variant, ByVal xChar As String) As String
Dim generalArray As Variant
If IsArray(rangeOrArray) Then
'operate on it as if was an array
generalArray = rangeOrArray
Else
If TypeName(rangeOrArray) = "Range" Then
'operate on it as if was a Range
If rangeOrArray.Cells.Count > 1 Then
generalArray = rangeOrArray.Value
Else
generalArray = Array(rangeOrArray.Value)
End If
Else
'Try to process as if it was a derivative of a value of a single cell range.....
generalArray = Array(rangeOrArray)
End If
End If
Dim xDic As Object
Set xDic = CreateObject("Scripting.Dictionary")
Dim xCell As Variant
For Each xCell In generalArray
If xCell <> False Then xDic(xCell) = Empty ' EDIT - HACKY....
Next
ConcatUniq = Join$(xDic.Keys, xChar)
End Function
You can see that that whole block of if-elses can be factored out to be a separate function to transform worksheet input to a unified form for operating on values of a worksheet.
The easiest solution would probably be to introduce an additional function. This function would take care of the condition and would generate an array consisting only of data fulfilling the condition.
Try something like this:
function condition_check(data1() as integer, data2() as string, condition_value as string) as integer
number_of_elements = Ubound(data1)
j = 0
for i = 0 to number_of_elements
if data2(i) = condition_value then
condition_check(j) = data1(i)
j = j+1
end if
next i
end function
I have a sub that creates a Collection and adds Collections inside it. But I get an Wrong number of arguments or invalid property assignment error when adding a first collection in the loop:
Sub testState()
Dim stateCopy As State
Set stateCopy = New State
stateCopy.setStateName="some name"
stateCopy.storeBudgetWorkbooks
stateCopy.storeBudgetDatas 'error on this line
End Sub
Sub storeBudgetDatas() 'inside a class named State
...
Dim year As Integer
Dim i As Integer
i = 1
For year = 2014 To 2017
Set budgetWorkbook =
ExcelApp.Application.Workbooks.Open(budgetWorkbooks(i))
MsgBox ("still here") 'this message appears
allBudgetItems.Add getBudgetData(budgetWorkbook, year) 'this line is likely to cause problems
MsgBox ("and here") 'this message doesn't appear
budgetWorkbook.Close
i = i + 1
Next
End Sub
Function getBudgetData(budgetWorkbook As Workbook, year As Integer)
...
Dim budgetItems As Collection
Set budgetItems = getBudgetItems(year)
... 'setting attributes
getBudgetData = budgetItems(year)
End Function
Function getBudgetItems(year As Integer)
...
Dim resultCollection As Collection
Set resultCollection = New Collection
Dim itemCopy As Item
Dim i As Integer
For i = LBound(budgetItemNames) To UBound(budgetItemNames)
Set itemCopy = New Item
... 'setting attributes
resultCollection.Add itemCopy
Next
Set getBudgetItems = resultCollection
End Function
I'm not sure what's wrong here. getBudgetItems returns a collection. getBudgetData returns a collection as well. I tried adding/removing parenthesis but to no avail.
Figured it out. There should have been Set getBudgetData = budgetItems(year) instead of getBudgetData = budgetItems(year).
Since you haven't shown us all the relevant parts of your code, the best I can do is guess you're missing a Set:
Function getBudgetData(budgetWorkbook As Workbook, year As Integer)
...
Dim budgetItems As Collection
Set budgetItems = getBudgetItems(year)
... 'setting attributes
Set getBudgetData = budgetItems(year) ' Need Set here
End Function
Can any one explain me to get the object entites count of the layer
using vba code acad
I think You should use SelectionSets
Public Sub SelsetByLayer()
Dim ss As AcadSelectionSet
Dim FilterType(0) As Integer
Dim FilterData(0) As Variant
FilterType(0) = 8 ' DXF code of Layer property
For I = 0 To ThisDrawing.Layers.Count
' ThisDrawing.SelectionSets.Item(0).Delete
Set ss = ThisDrawing.SelectionSets.Add("test") ' You need to ensure if such selection set not exist yet .
FilterData(0) = ThisDrawing.Layers.Item(I).Name
ss.Select acSelectionSetAll, , , FilterType, FilterData
Next
End Sub
Further to the original answer, about using selection sets.
Here it is slightly modified:
Public Sub SelsetByLayer()
Dim ss As AcadSelectionSet
Dim FilterType(0) As Integer
Dim FilterData(0) As Variant
FilterType(0) = 8 ' DXF code of Layer property
For I = 0 To ThisDrawing.Layers.Count
Set ss = CreateSelectionSet("test")
FilterData(0) = ThisDrawing.Layers.Item(I).Name
ss.Select acSelectionSetAll, , , FilterType, FilterData
Next
End Sub
Public Function CreateSelectionSet(SelName As String) As AcadSelectionSet
On Error Resume Next
' Create a new selection set
' Delete any existing selection set with the specified name
With ThisDrawing
Set CreateSelectionSet = .SelectionSets.Add(SelName)
If (Err.Number <> 0) Then
Err.Clear
.SelectionSets.Item(SelName).Delete
Set CreateSelectionSet = .SelectionSets.Add(SelName)
End If
End With
End Function
I have added in the missing method for managing the deletion of existing selection set.
ss.Count will have the number of entities found. But please bear in mind that you may have layers frozen off etc. in the drawing and I think these will be excluded from the totals.
This is far beyond my skill set, frankly, I have never done anything like this and don't know if it is possible. The procedure below builds an array based on the values of column B6.
Private Sub dsbPositionBoard_Startup() Handles Me.Startup
'This event runs when the dsbPositionBoard starts. The procedure
'checks for the values in column A of the allPositionsAnualized sheet
'and populates the combobox with those values. If there are no values the box
'is disabled.
Dim xlRng As Excel.Range
Dim strRngArr As String
Dim strChkRange As String
Try
xlWB = CType(Globals.ThisWorkbook.Application.ActiveWorkbook, Excel.Workbook)
xlWS = DirectCast(xlWB.Sheets("allPositionsAnnualized"), Excel.Worksheet)
xlRng = DirectCast(xlWS.Range("B6", xlWS.Range("B6").End(Excel.XlDirection.xlDown)), Excel.Range)
strRngArr = String.Empty
strChkRange = CStr(xlWS.Range("B6").Value)
If (String.IsNullOrEmpty(strChkRange)) Then
cmbSelectPosition.Enabled = False
Else
'Build a string array delimited by commas
For i As Integer = 1 To xlRng.Rows.Count
Dim xlRngCell As Excel.Range = DirectCast(xlRng.Rows(i), Excel.Range)
strRngArr &= DirectCast(xlRngCell.Value.ToString, String) & ","
Next
strRngArr = strRngArr.Remove(strRngArr.Length - 1, 1)
cmbSelectPosition.Items.AddRange(strRngArr.Split(","c))
xlRng = Nothing
xlWS = Nothing
End If
Catch ex As Exception
MsgBox("There no positions available to select", CType(vbOKOnly, MsgBoxStyle), "Empty Selection")
End Try
End Sub
Now, the function below is used to select the value of cell range, pass it to a helper cell (B37) and then select the corresponding sheet. The value that this function passes to the helper cell has an equal value in the array above.
Private Function MoveBtwSheets(range As String) As String
'This function is used to toggle between the position board
'and the employee board. The function is utilized to select
'the employees listed in the position board, click on the radio button
' and open that employees information in the employee board
'#parameter range: Selects the cell with the employee name
Dim xlCalc As Excel.Worksheet
strMessage = "This employee does not exist. Please verify the employee name"
strCaption = "Selection Error"
msgBoxType = MessageBoxIcon.Error
msgBoxBtns = MessageBoxButtons.OK
xlWB = CType(Globals.ThisWorkbook.Application.ActiveWorkbook, Excel.Workbook)
xlCalc = CType(xlWB.Worksheets("calculationSheets"), Excel.Worksheet)
xlWSEE = CType(xlWB.Worksheets("employeeBoard"), Excel.Worksheet)
xlWSPOS = CType(xlWB.Worksheets("positionBoard"), Excel.Worksheet)
Application.ScreenUpdating = False
Try
xlCalc.Range("B36").Value = xlWSPOS.Range(range).Value
With xlWSEE
.Select()
.Range("E37").Select()
End With
Application.ScreenUpdating = True
Catch ex As Exception
MessageBox.Show(strMessage, strCaption, msgBoxBtns, msgBoxType)
End Try
Return ""
End Function
So what I wanted to do add to my function is a way to search my array for the value on B37 and then display that value in the combobox in the first procedure. Basically, instead of me dropping down and selecting the item from the array, function would search the array for me and select that item.
If I am not very clear, I can clarify or post screen shots.
This would be a great time to use LINQ. In your initial method (dsbPositionBoard_Startup()), you can add each string in Column A into a List(Of String). Then you can query the list using the value of B37 as your search parameter.
Declare the list at the top of your class (outside of any methods)
Private _myList As New List(Of String)
Add this code to your first method
strRngArr = strRngArr.Remove(strRngArr.Length - 1, 1)
cmbSelectPosition.Items.AddRange(strRngArr.Split(","c))
_myList.Add(strRngArr.Split(","c))
xlRng = Nothing
xlWS = Nothing
Now add a function along the following lines:
Private Function QueryValues(ByVal myParameter as String) As String
Dim results = From result In _myList Where result = myParameter Select result Distinct
Return results(0)
End Function
Call that function (add some error handling/null reference checks though) with your parameter being the value of cell B37 (or any cell value as string).