Questions similar to this appear on the Bentley Discussion Groups. This question arose on the MicroStation Programming Forum.
If you're interested in programming Text Styles with VBA, there's a separate page.
If you're interested in analysing Numeric Text with VBA, there's a separate page.
Q How do I get the origin of a TextElement ?
A
TextElement.Origin
is actually the User Origin value displayed in the Element Information dialog.
TextElement
does not provide a property that provides access to the value displayed as Origin.
If you want to get that coordinate, use a Property Handler …
Sub TraceTextOrigin (ByVal oText As TextElement) Dim originValue As Point3d Dim oPropertyHandler As PropertyHandler Set oPropertyHandler = CreatePropertyHandler(oText) PropertyHandler.SelectByAccessString "Origin" originValue = PropertyHandler.GetValueAsPoint3d Debug.Print "Origin is " & originValue.X; ", " & originValue.Y & ", " & originValue.Z PropertyHandler.SelectByAccessString "UserOrigin" originValue = PropertyHandler.GetValueAsPoint3d Debug.Print "UserOrigin is " & originValue.X; ", " & originValue.Y & ", " & originValue.Z End Sub
Q How do I extract the boundary of a TextElement ? How do I extract the boundary when the TextElement is rotated?
A
A TextElement 's Boundary
is a UDT with Low
and High
components, each a Point3d
.
If the TextElement is not rotated, then these points can be used to construct a rectangle that represents the
TextElement 's boundary.
When a TextElement is rotated the Boundary.Low
and Boundary.High
points
are modified so that they continue to provide the lowest and highest coordinates that bound the element.
If you attempt to construct a rectangle from the boundary points of a rotated TextElement , you end up with
something that appears to have little to do with the TextElement you started with.
The solution is to unrotate the TextElement before extracting its Boundary.Low
and Boundary.High
points.
Then derive a rectangle from those points, and rotate the rectangle to the TextElement 's original rotation.
The VBA Project TextAnalysis is available in ZIP archive TextAnalysis.zip. The project illustrates how to extract a valid text boundary from rotated or unrotated TextElement s. The code implements a model scanner that extracts boundary data from each TextElement , then creates a ShapeElement corresponding to that boundary.
The key procedure in the project is the function ExtractBoundary
. The essential code of
ExtractBoundary
is shown below, less error statements.
Function ExtractBoundary(ByRef points() As Point3d, ByVal oText As TextElement) As Boolean ExtractBoundary = False Dim oRotation As Matrix3d Dim oTransform As Transform3d' Save the Text Element's rotation
oRotation = oText.Rotation' Create a transformation from the inverse of the rotation about the text origin
oTransform = Transform3dFromMatrix3dAndFixedPoint3d(Matrix3dInverse(oRotation), oText.origin)' Unrotate the Text Element (but don't rewrite it)
oText.Transform oTransform' Create a rectangle's vertices from the unrotated Text Element's boundary
Dim i As Integer For i = 0 To 4 points(i) = oText.Boundary.Low Next i points(2) = oText.Boundary.High points(1).X = points(2).X points(3).Y = points(2).Y' Create a transformation to rotate the points to match the original Text Element
oTransform = Transform3dFromMatrix3dAndFixedPoint3d(oRotation, oText.origin)' Transform the boundary rectangle to the original rotation
For i = 0 To 4 points(i) = Point3dFromTransform3dTimesPoint3d(oTransform, points(i)) Next i ExtractBoundary = True End Function
You can download the VBA TextAnalysis Project as a ZIP archive.
Unpack the ZIP archive and extract TextAnalysis.mvba
to a suitable location, such as
C:\Program Files\Bentley\Workspace\Standards\MVBA
.
Q How do I get the DGN size of a TextElement?
A
A TextElement 's DGN size is the width and height in model units.
The VB/VBA Len$()
function gets the number of characters in a text string.
You can get a TextElement's width and height using method TextElement.GetTotalTextSize
.
Here's an example where we copy the width and height into a Point2d
user-defined-type (UDT) …
Dim size As Point2d oText.GetTotalTextSize size.X, size.Y
Q How do I compare width or height of two TextElements?
A
A TextElement 's DGN size is the width and height in model units.
Use method TextElement.GetTotalTextSize
to get the width & height of your two text elements.
Then, use simple arithmetic comparison to decide which is the larger.
Here's an example function that returns the greater width of two text elements.
You can write a similar function that returns the greater height of two text elements …
' ---------------------------------------------------------------------
' GetMaxTextWidth
' Returns the greater of the widths of two text elements.
' This is the geometric width of the text element in a DGN model,
' not its character count returned by Len$()
' Returns: [Double] Greater of the widths of Text1 and Text2
' ---------------------------------------------------------------------
Function GetMaxTextWidth(ByVal oText1 As TextElement, ByVal oText2 As TextElement) As Double
Dim size1 As Point2d
Dim size2 As Point2d
oText1.GetTotalTextSize size1.X, size1.Y
oText2.GetTotalTextSize size2.X, size2.Y
Debug.Print "Text1 width " & CStr(size1.X)
Debug.Print "Text2 width " & CStr(size2.X)
GetMaxTextWidth = size1.X
If (size2.X > size1.X) Then
GetMaxTextWidth = size2.X
End If
End Function
Q How do I increment the value of a TextElement ? How do I change 500 TextElements automatically?
A The best by far method is to purchase a license for FlexiTable™. FlexiTable provides ways to review, create and modify text. Text modification methods work using formulæ similar to those you find in Excel™. However, since you're reading this you must be a VBA programmer, so skip this flagrant self-promotion and get into the nitty-gritty!
You change lots of elements at once by scanning a model. Use an ElementScanCriteria
class
to filter TextElements, then use the ActiveModelReference.Scan
method to obtain an
ElementEnumerator
. The enumerator is, put simply, a traversable list of elements that pass the
scan criteria test.
Once you have each element, in this case a TextElement, you can do with it what you want. In this example, what we want to do is add a number to TextElements that have a numeric content. In other words, we want to find TextElements that contain a number, add (or subtract) an amount to that number, then update the TextElement …
You can download the VBA Change Numeric Text Project as a ZIP archive.
Unpack the ZIP archive and extract ChangeNumericText.mvba
to a suitable location, such as
C:\Program Files\Bentley\Workspace\Standards\MVBA
.
To run this utility keyin …
vba run [ChangeNumericText]modMain.Main <delta>
where <delta>
is the positive or negative number to apply
Q How do I set the active text settings and place text?
A First of all, consider using a text style rather than manipulating the active settings. Like paragraph styles in a text processor, such as Microsoft Word™, text styles allow you to define consistent settings. You can apply the same text style to a set of text elements, and then, if you need the text to look different, simply change the text style.
However, you want to know how to modify settings using VBA, rather than read my rants about super-duper features of MicroStation. The answer is very simple. So simple, in fact, that the code speaks for itself …
' --------------------------------------------------------------------- ' Set Text Size ' Set the current text height & width ' ---------------------------------------------------------------------
Sub SetTextSize(ByVal size As Double) If (0 < size) Then ActiveSettings.TextStyle.Height = size ActiveSettings.TextStyle.Width = size End If End Sub' --------------------------------------------------------------------- ' Place custom text: text size 10, place 'X' ' ---------------------------------------------------------------------
Sub PlaceCustomText() SetTextSize 10 Const command As String = "PLACE TEXT ICON;" Dim text As String' Change this text to whatever you want
text = "X" Debug.Print "This is the command sent to MicroStation: " & command & text CadInputQueue.SendCommand command & text, True End Sub