I've the following code:
Dim headerTextboxes(2) As Shape
Dim currSlide As Slide
Set currSlide = Application.ActiveWindow.View.Slide
' Pseudocode
' Set currSlide = [null, null, null]
For i = 0 to 2
headerTextboxes(i) = currSlide.Shapes.AddTextbox(...)
Next i
I'm getting the error Object variable or With block variable not set. After some research, I believe it's because no array has actually been assigned to headerTextboxes yet.
The pseudocode in the comments is that I want to do. What's the correct implementation for it? All I can find online is to initialise either a zero-length array or a static length array with existing elements.
You need to use the Set keyword to when setting a reference to an Object. Since headerTextboxes is an array of Shape Objects, every element must use Set to assign a reference to a Shape.
Dim headerTextboxes(2) As Shape
Dim currSlide As Slide
Set currSlide = Application.ActiveWindow.View.Slide
' Pseudocode
' Set currSlide = [null, null, null]
For i = 0 To 2
Set headerTextboxes(i) = currSlide.Shapes.AddTextbox(...)
Next i
Related
I have a grouped shape in a document:
Dim doc As Word.Document
Set doc = Documents("dlr-overview.docx")
Dim firstShape As Word.Shape
Set firstShape = doc.Shapes(1)
AutoShapeType on firstShape returns -2, or msoShapeMixed; and firstShape.GroupItems.Count returns 25:
Debug.Print firstShape.AutoShapeType
Debug.Print firstShape.GroupItems.Count
I can iterate over the shapes in firstShape.GroupItems without casting to Shape. TypeName returns "Shape" for each element, and the AutoShapeType property returns 5, or msoShapeRoundedRectangle:
Dim x As Variant
For Each x In firstShape.GroupItems
Debug.Print TypeName(x)
Debug.Print x.AutoShapeType
Next
But when I try to cast each element to Shape, I get Type mismatch on the first iteration of the For Each:
Dim subshape As Shape
For Each subshape In firstShape.GroupItems
Debug.Print subshape.Left
Next
How can I extract information about an individual shape from the grouped shape?
It seems that it is impossible to enumerate using a Shape variable over the GroupShapes object returned from Shape.GroupItems. The following also errors within the iteration:
Dim shapes As GroupShapes
Set shapes = firstShape.GroupItems
Dim shp As Shape
For Each shp In shapes
Debug.Print shp.Name
Next
Apparently the returned elements are something other than Word.Shape objects, even though the TypeName function returns "Shape" for such objects.
However, if I access the elements via the Item property of the GroupShapes collection, or via the default property, they are returned as Word.Shape objects, and can be casted to Word.Shape:
Dim i As Integer
For i = 1 To firstShape.GroupItems.Count
Dim shp As Shape
Set shp = firstShape.GroupItems(i)
Debug.Print shp.Name
Next
I am trying to get the length of user selected lines/splines
This is the code I'm using to have users select their lines:
Dim USel As Selection
Dim USelLB
Dim InputObject(0)
InputObject(0) = "AnyObject"
Set USel = CATIA.ActiveDocument.Selection
Set USelLB = USel
USel.Clear
USelLB.Clear
Linestomeasure = USelLB.SelectElement3(InputObject, "Select objects to list names", True, CATMultiSelTriggWhenUserValidatesSelection, False)
Linestomeasure is a public variable, in the mainsub i've been trying to measure Linestomeasure using the following code:
Dim pd1 As PartDocument
Dim a As Object
Dim c As Reference
a = TrimLines.Item(1)
c = pd1.Part.CreateReferenceFromObject(a)
Dim Mea1 As Measurable
Dim TheSPAWorkbench As SPAWorkbench
Set TheSPAWorkbench = pd1.GetWorkbench("SPAWorkbench")
Set Mea1 = TheSPAWorkbench.GetMeasurable(c)
But when I run the code a = trimLines.Item(1) gets highlighted in the debugger with the error message "Object Required".
Does anyone have an idea on how I can change my code so that I can get the length of the line as a variable that I can work with ? Or just a different way to go about what I'm trying to do?
Edited answer to reflect comment bellow
Looks like you are assigning the wrong type of variable to the USelLB.SelectElement3 and also missunderstanding how it actually works.
The Selection.SelectElement3 returns a String that reflects whether the selection was sucessfull or not.
The Object retrieved from the Selection is inside the Selection.Item(Index)
Your code should be something like this:
Dim PD1 as PartDocument
Dim Sel 'as Selection 'Sometimes it is needed to comment the selection to use the .SelectElement3 method
Dim InputObjType(0)
Dim SelectionResult as string
Dim LineToMeasure as AnyObject
Dim I as Integer
Dim SpaWorkbench as SPAWorkbench
Dim Measurable as Measurable
InputObjType(0) = "AnyObject"
'set PD1 = Catia.ActiveDocument
set Sel = PD1.Selection
Set TheSPAWorkbench = pd1.GetWorkbench("SPAWorkbench")
Sel.Clear
SelectionResult= Sel.SelectElement3(InputObject, "Select objects to list names", True, CATMultiSelTriggWhenUserValidatesSelection, False)
If SelectionResult = "Ok" or SelectionResult = "Normal" then 'Check if user did not cancel the Selection
For i = 1 to Selection.Count
Set LineToMeasure = Sel.Item(i).Value
set Measurable = SpaWorkbench.GetMeasurable(LineToMeasure)
'Measure whatever you need here.
Next
End If
Keep in mind that using the AnyObject type filter may cause the user to select unwanted objects. You shoudl use a more specific filter.
I am trying to create a dynamic number of variables in VBA based on the value in a cell.
Essentially what I'd like to end up with is something like Team1, Team2... to TeamX.
Any help is greatly appreciated
Dim i, x As Integer
Set x = Range("J4").Value
Dim Team(1 To x) As String
Dim Manager(1 To x) As String
Range("A3").Select
For i = 1 To x
Dim Team(i) As Integer
A dictionary would probably help in this case, it's designed for scripting, and while it won't let you create "dynamic" variables, the dictionary's items are dynamic, and can serve similar purpose as "variables".
Dim Teams as Object
Set Teams = CreateObject("Scripting.Dictionary")
For i = 1 To x
Teams(i) = "some value"
Next
Later, to query the values, just call on the item like:
MsgBox Teams(i)
Dictionaries contain key/value pairs, and the keys must be unique. Assigning to an existing key will overwrite its value, e.g.:
Teams(3) = "Detroit"
Teams(3) = "Chicago"
Debug.Print Teams(3) '## This will print "Chicago"
You can check for existence using the .Exist method if you need to worry about overwriting or not.
If Not Teams.Exist(3) Then
Teams(3) = "blah"
Else:
'Teams(3) already exists, so maybe we do something different here
End If
You can get the number of items in the dictionary with the .Count method.
MsgBox "There are " & Teams.Count & " Teams.", vbInfo
A dictionary's keys must be integer or string, but the values can be any data type (including arrays, and even Object data types, like Collection, Worksheet, Application, nested Dictionaries, etc., using the Set keyword), so for instance you could dict the worksheets in a workbook:
Dim ws as Worksheet, dict as Object
Set dict = CreateObject("Scripting.Dictionary")
For each ws in ActiveWorkbook.Worksheets
Set dict(ws.Name) = ws
Next
This will get you started. But before you start I recommend watching these WiseOwlTutorials tutorial on Youtube:
Selecting Cells (Range, Cells, Activecell, End, Offset)
Worksheets, Charts and Sheets
Variables
Arrays
Dim i, x As Integer
x = Range("J4").Value
Dim Team() As Integer
Dim Manager() As String
ReDim Team(1 To x) As Integer
ReDim Manager(1 To x) As String
Range("A3").Select
For i = 1 To x
Team(i) = i
Next
I am trying to build some code that inserts a name and email address in to the next open row from the next row in the loop. I am getting an error in Set = Number of Emails line and I am not sure why.
Sub Email_Copy()
Dim Data As Worksheet
Set Data = ActiveWorkbook.Sheets("Data")
Dim Email_Database As Worksheet
Set Email_Database = ActiveWorkbook.Sheets("Email_Database")
Dim Number_Of_Emails As Integer
Set Number_Of_Emails = Data.Range("L6002")
Dim Total_Emails As Long
Set Total_Emails = Email_Database.Range("D2")
Dim X As Long
For X = 1 To Number_Of_Emails
Set Email_Database.Range("B3").Offset(Total_Emails, 0) = Data.Range("D3").Offset(Number_Of_Emails, 0)
End Sub
You declared Number_Of_Emails As Integer but then tried to set it to a range so it's a type mismatch. You can simply do
Number_Of_Emails = Data.Range("L6002").value
Edit: to plagarize Scott Holtzman's comment verbatim
Set is only required with Object Type variables (hence the error). A
Range variable is an Object Type. An Integer, being a number, is not
an object type. (String is not on object either). Worksheet is an
Object Type.
I would like to know what I'm doing wrong...
I have a word document open (in word 2010) with three tables in it. I wanted to test basic table extraction in VBA and followed the instructions http://msdn.microsoft.com/en-us/library/office/aa537149(v=office.11).aspx.
Sub ExtractTableData()
Dim doc As Word.Document
Dim tbl As Word.Table
Dim rng As Word.Range
Dim sData As String
Dim aData1() As String
Dim aData2() As String
Dim aDataAll() As String
Dim nrRecs As Long
Dim nrFields As Long
Dim lRecs As Long
Dim lFields As Long
Set doc = ActiveDocument
Set tbl = doc.Tables(1)
Set rng = tbl.ConvertToText(Separator:=vbTab, _
NestedTables:=False)
' Pick up the delimited text into and put it into a string variable.
sData = rng.Text
' Restore the original table.
doc.Undo
' Strip off last paragraph mark.
sData = Mid(sData, 1, Len(sData) - 1)
' Break up each table row into an array element.
aData1() = Split(sData, vbCr)
nrRecs = UBound(aData1())
' The messagebox below is for debugging purposes and tells you
' how many rows are in the table. It is commented out but can
' be used simply by uncommenting it.
'MsgBox "The table contained " & nrRecs + 1 & " rows"
'Process each row to break down the field information
'into another array.
For lRecs = LBound(aData1()) To nrRecs
aData2() = Split(aData1(lRecs), vbTab)
' We need to do this only once!
If lRecs = LBound(aData1()) Then
nrFields = UBound(aData2())
ReDim Preserve aDataAll(nrRecs, nrFields)
End If
' Now bring the row and field information together
' in a single, two-dimensional array.
For lFields = LBound(aData2()) To nrFields
aDataAll(lRecs, lFields) = aData2(j)
Next
Next
End Sub
I'm getting an error at this line: ReDim Preserve aDataAll(nrRecs, nrFields), which is due to "nrFields" being set to a negative value (-1)...
No idea how the upper bound of the array is a negative value... Any help on this would be much appreciated.
I figured it out - I was trying to extract a nested table. I had to cycle through all sub-tables and extract individually. Also, I had to search for and remove ^p before extraction to retain table structure.
After I had figured it out, I noticed that the MS code sample had an error: aData2(j) should actually be aData2(lFields).
Hope this helps some other newbie!
If UBound is -1 and LBound = 0, the array is empty. You can generate an empty array as follows:
Dim EmptyArray() As String
Dim s As String
EmptyArray = Split("")
Debug.Print (UBound(EmptyArray)) ' displays -1
Debug.Print (LBound(EmptyArray)) ' displays 0
In your case I suspect you need to skip the processing if the array is empty:
aData1 = Split(...)
If (UBound(aData1) < LBound(aData1) Then
' UBound is -1 and LBound is 0, array is empty, nothing to do
Else
' Array is non-empty, do your stuff
End If
Although quite bizarre, it is possible for VARIANT SAFEARRAY to have negative lower and upper bound values for any of the dimensions. The array extent is LBound(,dimension) to UBound(,dimension).
What must be true is UBound >= LBound.
To get the array size, use UBound - LBound + 1.
It used to be convention to set the lower bound using an Option Base statement at the top of VBA code although, of course, that didn't affect arrays being returned by 3rd party libraries. Most folk used to use 1 as the lower bound.