StringFormat class

Describes how a string is laid out when it is drawn or measured: alignment, wrapping, trimming, tab stops and more.

A StringFormat is passed to the DrawString and MeasureString methods of Graphics, beside the Font and the layout rectangle. A format that is omitted gives the default layout: the text is aligned to the top left, wraps at the edge of the rectangle, and is trimmed to a whole character. The settings of a format are independent of each other, and each is set by a property, or by a Set… method that names the value. The class mirrors the GDI+ StringFormat class.

Creating

Syntax: format = StringFormat( [ flags [, language] ] )

Syntax: format = New StringFormat( [ flags [, language] ] )

flags
optional A GpStringFormatFlags value or a combination of them. The default is 0: no flag is set.
language
optional An Integer language identifier (a LANGID) for the language of the strings. The default is 0, the neutral language.

A new format has these other settings: near alignment in both directions, trimming to a whole character, no hot key processing, no tab stops, no measurable character ranges and the digit substitution method StringDigitSubstituteUser.

Clone

Syntax: copy = format.Clone( )

Returns a new StringFormat with the same settings.

GenericDefaultStringFormat, GenericTypographicStringFormat

Syntax: format = GenericDefaultStringFormat( )

Syntax: format = GenericTypographicStringFormat( )

GenericDefaultStringFormat returns the format that GDI+ uses when none is given. It has no flags, near alignment and trimming to a whole character. GenericTypographicStringFormat returns a format for typographic layout, with the flags NoFitBlackBox, LineLimit and NoClip and no trimming.

Note 0.9.45.0

Both functions return the shared generic format of GDI+, not a copy. Changing the object changes the generic format for the whole program, and a later call returns the changed format. Call Clone and change the copy instead.

Dim user As GdiPlusUser = GdiPlusUser()

Dim d As StringFormat = GenericDefaultStringFormat()
Debug.Print d.Flags                 ' 0
Debug.Print d.IsTrimmingCharacter   ' True

Dim t As StringFormat = GenericTypographicStringFormat()
Debug.Print t.NoFitBlackBox & " " & t.LineLimit & " " & t.NoClip   ' True True True
Debug.Print t.IsTrimmingNone                                      ' True

' The generic format is shared: this change is seen by every later call.
d.NoWrap = True
Debug.Print GenericDefaultStringFormat().NoWrap   ' True
d.NoWrap = False

Dim mine As StringFormat = GenericDefaultStringFormat().Clone()
mine.NoWrap = True
Debug.Print GenericDefaultStringFormat().NoWrap   ' False

Format flags

Flags

Syntax: format.Flags [ = flags ]

Returns or sets all the flags together, as a GpStringFormatFlags combination. FormatFlags is an older name of the same property, kept for compatibility.

The flag properties

Syntax: format.NoWrap [ = value ]

Each of these properties is a Boolean that reads or sets one flag and leaves the others as they are.

Property Flag When True
DirectionRightToLeft StringFormatFlagsDirectionRightToLeft The text is laid out from right to left.
DirectionVertical StringFormatFlagsDirectionVertical The lines of text are vertical, not horizontal.
NoFitBlackBox StringFormatFlagsNoFitBlackBox Parts of a glyph may extend beyond the layout rectangle. By default GDI+ moves the glyph to keep it inside.
DisplayFormatControl StringFormatFlagsDisplayFormatControl Control characters, such as the right-to-left mark, are drawn with a representative glyph.
NoFontFallback StringFormatFlagsNoFontFallback A character that the font lacks is not drawn with another font. It is drawn with the font’s missing-character glyph, usually an open square.
MeasureTrailingSpaces StringFormatFlagsMeasureTrailingSpaces The bounding box of a measured string includes the spaces at the end of each line. By default it does not.
NoWrap StringFormatFlagsNoWrap The text is not wrapped to the next line at the edge of the layout rectangle.
LineLimit StringFormatFlagsLineLimit Only whole lines are laid out in the rectangle. By default a line that fits only in part is drawn in part.
NoClip StringFormatFlagsNoClip The text is not clipped to the layout rectangle: glyphs that extend beyond it, and text that falls outside it, are drawn.
BypassGDI StringFormatFlagsBypassGDI A flag that GDI+ declares. Microsoft’s documentation does not describe its effect.
Dim user As GdiPlusUser = GdiPlusUser()

Dim sf As StringFormat = StringFormat(StringFormatFlagsNoWrap)
Debug.Print sf.NoWrap & " " & sf.LineLimit    ' True False

sf.LineLimit = True
sf.DirectionRightToLeft = True
Debug.Print sf.Flags    ' 12289
Debug.Print sf.Flags = (StringFormatFlagsNoWrap Or StringFormatFlagsLineLimit Or StringFormatFlagsDirectionRightToLeft)    ' True

sf.NoWrap = False
Debug.Print sf.Flags    ' 8193

Horizontal alignment

The alignment places each line along its direction. StringAlignmentNear is the left edge for left-to-right text, the right edge for right-to-left text and the top for vertical text. StringAlignmentFar is the opposite edge, and StringAlignmentCenter the middle. The values are GpStringAlignment.

Alignment

Syntax: format.Alignment [ = alignment ]

Returns or sets the alignment.

SetAlignmentNear, SetAlignmentCenter, SetAlignmentFar

Syntax: format.SetAlignmentFar

Each method sets the alignment to the value in its name.

IsAlignmentNear, IsAlignmentCenter, IsAlignmentFar

Syntax: format.IsAlignmentNear

Each read-only property returns True when the alignment is the value in its name. They are unreliable: see the warning on Alignment.

Dim user As GdiPlusUser = GdiPlusUser()

Dim bmp As Bitmap = Bitmap(100!, 30!)
Dim g As Graphics = Graphics(bmp)
Dim f As GdiPlus.Font = Font(GenericSansSerif(), 12!)
Dim black As SolidBrush = SolidBrush(Color(255, 0, 0, 0))
Dim layout As GpRectF = GpRectF(0, 0, 100, 30)
Dim sf As StringFormat = StringFormat()
sf.SetAlignmentFar

g.Clear White
g.DrawString "I", f, layout, sf, black

' Find the dark pixels: with far alignment they are all in the right half.
Dim x As Long, y As Long, inkLeft As Boolean, inkRight As Boolean
For y = 0 To 29
    For x = 0 To 99
        If bmp.Pixel(x, y).argb <> White Then
            If x < 50 Then inkLeft = True Else inkRight = True
        End If
    Next
Next
Debug.Print inkLeft & " " & inkRight    ' False True

Vertical alignment

The line alignment places the block of lines across the direction of the text: StringAlignmentNear is the top of the layout rectangle for horizontal text, StringAlignmentFar the bottom, and StringAlignmentCenter the middle.

LineAlignment

Syntax: format.LineAlignment [ = alignment ]

Returns or sets the line alignment, a GpStringAlignment value.

SetLineAlignmentNear, SetLineAlignmentCenter, SetLineAlignmentFar

Syntax: format.SetLineAlignmentCenter

Each method sets the line alignment to the value in its name.

IsLineAlignmentNear, IsLineAlignmentCenter, IsLineAlignmentFar

Syntax: format.IsLineAlignmentNear

Each read-only property returns True when the line alignment is the value in its name.

Dim user As GdiPlusUser = GdiPlusUser()

Dim sf As StringFormat = StringFormat()
sf.SetLineAlignmentCenter
Debug.Print sf.LineAlignment & " " & sf.IsLineAlignmentCenter   ' 1 True

sf.LineAlignment = StringAlignmentFar
Debug.Print sf.IsLineAlignmentFar & " " & sf.IsLineAlignmentNear   ' True False

Hot key prefix

A hot key prefix is the ampersand (&) that marks the character before which an access key is shown, as in &File. The values are GpHotkeyPrefix. The default, HotkeyPrefixNone, draws the ampersand as it is.

HotkeyPrefix

Syntax: format.HotkeyPrefix [ = prefix ]

Returns or sets how the ampersand is processed: HotkeyPrefixNone draws it, HotkeyPrefixShow removes it and underlines the next character, and HotkeyPrefixHide removes it and does not underline.

SetHotkeyPrefixNone, SetHotkeyPrefixShow, SetHotkeyPrefixHide

Syntax: format.SetHotkeyPrefixShow

Each method sets the processing to the value in its name.

IsHotkeyPrefixNone, IsHotkeyPrefixShow, IsHotkeyPrefixHide

Syntax: format.IsHotkeyPrefixShow

Each read-only property returns True when the processing is the value in its name.

Dim user As GdiPlusUser = GdiPlusUser()

Dim sf As StringFormat = StringFormat()
Debug.Print sf.IsHotkeyPrefixNone    ' True

sf.SetHotkeyPrefixShow
Debug.Print sf.HotkeyPrefix & " " & sf.IsHotkeyPrefixShow    ' 1 True

sf.HotkeyPrefix = HotkeyPrefixHide
Debug.Print sf.HotkeyPrefix & " " & sf.IsHotkeyPrefixHide    ' 2 True

Trimming

Trimming decides what happens to the end of a line that does not fit in the layout rectangle. The values are GpStringTrimming. The default is StringTrimmingCharacter.

Value The line is
StringTrimmingNone Not trimmed.
StringTrimmingCharacter Cut at the last character that fits.
StringTrimmingWord Cut at the last word that fits.
StringTrimmingEllipsisCharacter Cut at the last character that fits, and an ellipsis is added.
StringTrimmingEllipsisWord Cut at the last word that fits, and an ellipsis is added.
StringTrimmingEllipsisPath Shortened in the middle: the centre is removed and replaced by an ellipsis, and as much as possible of the last part of a path is kept.

Trimming

Syntax: format.Trimming [ = trimming ]

Returns or sets the trimming.

SetTrimmingNone, SetTrimmingCharacter, SetTrimmingWord, SetTrimmingEllipsisCharacter, SetTrimmingEllipsisWord, SetTrimmingEllipsisPath

Syntax: format.SetTrimmingEllipsisWord

Each method sets the trimming to the value in its name.

IsTrimmingNone, IsTrimmingCharacter, IsTrimmingWord, IsTrimmingEllipsisCharacter, IsTrimmingEllipsisWord, IsTrimmingEllipsisPath

Syntax: format.IsTrimmingWord

Each read-only property returns True when the trimming is the value in its name.

Dim user As GdiPlusUser = GdiPlusUser()

Dim sf As StringFormat = StringFormat()
Debug.Print sf.Trimming & " " & sf.IsTrimmingCharacter    ' 1 True

sf.SetTrimmingEllipsisPath
Debug.Print sf.Trimming & " " & sf.IsTrimmingEllipsisPath    ' 5 True

sf.Trimming = StringTrimmingEllipsisWord
Debug.Print sf.IsTrimmingEllipsisWord & " " & sf.IsTrimmingEllipsisPath    ' True False

Tab stops

Tab stops set where a tab character in the text moves the characters after it. The first tab stop is measured from an initial offset, which is measured from the string’s origin, and each later tab stop from the one before it.

TabStopCount

Syntax: format.TabStopCount

Returns a Long with the number of tab stops that are set.

SetTabStops

Syntax: status = format.SetTabStops( firstTabOffset, tabStops() )

Syntax: status = format.SetTabStops( firstTabOffset, count, tabStops )

firstTabOffset
required A Single with the initial offset, the distance from the origin of the string to the point that the first tab stop is measured from.
tabStops
required In the first form, an array of Single values, each the distance between a tab stop and the one before it. The lower bound of the array does not matter. In the second form, the first element of such an array, passed ByRef.
count
required A Long with the number of elements to take, in the second form.

Replaces the tab stops of the format and returns a GpStatus.

GetTabStops

Syntax: tabStops = format.GetTabStops( firstTabOffset )

Syntax: status = format.GetTabStops( count, firstTabOffset, tabStops )

firstTabOffset
required A Single variable that receives the first tab offset.
count
required A Long with the number of elements to read, in the second form.
tabStops
required In the second form, the first element of an array of Single values with room for count elements. It receives the tab stops.

The first form returns the tab stops as a one-based array of Single values. The second form fills an array that the caller has made and returns a GpStatus.

Digit substitution

Digit substitution draws the digits 0 to 9 of a string with the digits of another script, such as Arabic-Indic digits. The language says which script. The methods are GpStringDigitSubstitute values: StringDigitSubstituteUser follows the user’s regional settings, StringDigitSubstituteNone turns the substitution off, StringDigitSubstituteNational uses the digits of the official language of the locale and StringDigitSubstituteTraditional uses the digits of the user’s native script, which can be a different language. A language identifier is an Integer, such as 1033 for US English.

DigitSubstitutionLanguage

Syntax: format.DigitSubstitutionLanguage [ = language ]

Returns or sets the language identifier. See the warning above for what setting it does.

DigitSubstitutionMethod

Syntax: format.DigitSubstitutionMethod [ = method ]

Returns or sets the method, a GpStringDigitSubstitute value. Setting it keeps the language.

SetDigitSubstitution

Syntax: status = format.SetDigitSubstitution( language, substitute )

language
required An Integer language identifier.
substitute
required A GpStringDigitSubstitute value.

Sets the language and the method together and returns a GpStatus.

SetDigitSubstitutionUser, SetDigitSubstitutionNone, SetDigitSubstitutionNational, SetDigitSubstitutionTraditional

Syntax: format.SetDigitSubstitutionNone

Each method sets the method to the value in its name. See the warning above: each also sets the language to 0.

IsDigitSubstitutionUser, IsDigitSubstitutionNone, IsDigitSubstitutionNational, IsDigitSubstitutionTraditional

Syntax: value = format.IsDigitSubstitutionNone( )

Each function returns True when the method is the value in its name.

Measurable character ranges

A format can name up to 32 ranges of characters in a string. Graphics.MeasureCharacterRanges then returns one Region for each range, which covers the space that the characters of the range take when the string is laid out. A range is a CharacterRange.

Note

GDI+ accepts at most 32 ranges. A call with more returns ValueOverflow and leaves the earlier ranges in place.

MeasurableCharacterRanges

Syntax: format.MeasurableCharacterRanges = ranges()

ranges
An array of CharacterRange values.

Sets the ranges. The property is write-only: read the number of ranges with MeasurableCharacterRangeCount.

SetMeasurableCharacterRanges

Syntax: status = format.SetMeasurableCharacterRanges( rangeCount, ranges )

rangeCount
required A Long with the number of ranges, at most 32.
ranges
required The first element of an array of CharacterRange values, passed ByRef.

Sets the ranges and returns a GpStatus.

MeasurableCharacterRangeCount

Syntax: format.MeasurableCharacterRangeCount

Returns a Long with the number of ranges that are set. It is 0 for a new format.

Dim user As GdiPlusUser = GdiPlusUser()

Dim bmp As Bitmap = Bitmap(100!, 50!)
Dim g As Graphics = Graphics(bmp)
Dim f As GdiPlus.Font = Font(GenericSansSerif(), 10!)
Dim layout As GpRectF = GpRectF(0, 0, 100, 50)
Dim sf As StringFormat = StringFormat()

Dim ranges(0 To 1) As CharacterRange
ranges(0) = CharacterRange(0, 3)    ' "abc"
ranges(1) = CharacterRange(4, 3)    ' "def"
sf.MeasurableCharacterRanges = ranges
Debug.Print sf.MeasurableCharacterRangeCount    ' 2

Dim regions() As Region = g.MeasureCharacterRanges("abc def", f, layout, sf)
Debug.Print UBound(regions) - LBound(regions) + 1    ' 2

' The count is limited to 32.
Dim many(0 To 32) As CharacterRange
Debug.Print sf.SetMeasurableCharacterRanges(32, many(0)) = Ok      ' True
Debug.Print sf.SetMeasurableCharacterRanges(33, many(0)) = ValueOverflow    ' True
Debug.Print sf.MeasurableCharacterRangeCount                       ' 32

See Also